- {{ virtualmachine.name }}
+
+ {{ virtualmachine.name }}
+
diff --git a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html
index 287757c..7311513 100755
--- a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html
+++ b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html
@@ -2,6 +2,12 @@
{% load render_table from django_tables2 %}
{% block content %}
+ TESTE TESTE TESTE
+
+
+ {{ virtualmachine.name }}
+
+
{% if perms.netbox_proxbox.add_proxmoxvm %}
Proxmox Full Update
diff --git a/netbox_proxbox/urls.py b/netbox_proxbox/urls.py
index d870873..433c589 100755
--- a/netbox_proxbox/urls.py
+++ b/netbox_proxbox/urls.py
@@ -29,6 +29,8 @@
path("
/delete/", ProxmoxVMDeleteView.as_view(), name="proxmoxvm_delete"),
path("/edit/", ProxmoxVMEditView.as_view(), name="proxmoxvm_edit"),
+
+
# Proxbox API full update
#path("full_update/", ProxmoxVMFullUpdate.as_view(), name="proxmoxvm_full_update")
path("full_update/", ProxmoxFullUpdate.as_view(), name="proxmoxvm_full_update")
From 0befcae7e47da35bc94ce4dfa5aca0c0662d5b04 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Fri, 17 Mar 2023 19:41:01 +0000
Subject: [PATCH 064/313] replace title with image of both systems integrated
---
.../static/netbox_proxbox/proxmox-logo.svg | 243 ++++++++++++++++++
netbox_proxbox/static/proxmox-logo.svg | 243 ++++++++++++++++++
.../templates/netbox_proxbox/home.html | 18 +-
.../proxmox_vm_full_update.html | 1 -
.../netbox_proxbox/proxmox_vm_list.html | 2 -
5 files changed, 501 insertions(+), 6 deletions(-)
create mode 100644 netbox_proxbox/static/netbox_proxbox/proxmox-logo.svg
create mode 100644 netbox_proxbox/static/proxmox-logo.svg
diff --git a/netbox_proxbox/static/netbox_proxbox/proxmox-logo.svg b/netbox_proxbox/static/netbox_proxbox/proxmox-logo.svg
new file mode 100644
index 0000000..bc5d22a
--- /dev/null
+++ b/netbox_proxbox/static/netbox_proxbox/proxmox-logo.svg
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/netbox_proxbox/static/proxmox-logo.svg b/netbox_proxbox/static/proxmox-logo.svg
new file mode 100644
index 0000000..bc5d22a
--- /dev/null
+++ b/netbox_proxbox/static/proxmox-logo.svg
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/netbox_proxbox/templates/netbox_proxbox/home.html b/netbox_proxbox/templates/netbox_proxbox/home.html
index 7243803..804e397 100644
--- a/netbox_proxbox/templates/netbox_proxbox/home.html
+++ b/netbox_proxbox/templates/netbox_proxbox/home.html
@@ -1,5 +1,5 @@
{% extends 'base/layout.html' %}
-
+{% load static %}
{% block content %}
@@ -13,6 +13,8 @@
{% endif %}
+
+
Proxbox Configuration
@@ -21,7 +23,12 @@
-
+
@@ -84,7 +91,12 @@
-
+
diff --git a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
index 87910a6..7d8ba28 100755
--- a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
+++ b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
@@ -1,5 +1,4 @@
{% extends 'base/layout.html' %}
-{% load render_table from django_tables2 %}
{% block content %}
diff --git a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html
index 7311513..ad3b1f3 100755
--- a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html
+++ b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_list.html
@@ -2,8 +2,6 @@
{% load render_table from django_tables2 %}
{% block content %}
- TESTE TESTE TESTE
-
{{ virtualmachine.name }}
From 5f093094e90621e87cc1f15e8bd832c0295753d8 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 12:14:45 +0000
Subject: [PATCH 065/313] fix duplicate update due to case sensitive mismatch
---
netbox_proxbox/proxbox_api/updates/virtual_machine.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/updates/virtual_machine.py b/netbox_proxbox/proxbox_api/updates/virtual_machine.py
index a46a432..64a0a3f 100755
--- a/netbox_proxbox/proxbox_api/updates/virtual_machine.py
+++ b/netbox_proxbox/proxbox_api/updates/virtual_machine.py
@@ -308,7 +308,7 @@ def interfaces(netbox_vm, proxmox_vm):
for _conf_str in interface[ifname].split(','):
_k_s =_conf_str.split('=')
if re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", _k_s[1].lower()):
- _mac_addr =_k_s[1].lower()
+ _mac_addr =_k_s[1].upper()
elif _k_s[0] == 'bridge':
_bridge = _k_s[1].lower()
elif _k_s[0] == 'mtu':
@@ -324,7 +324,7 @@ def interfaces(netbox_vm, proxmox_vm):
_pmx_if.append({'name': ifname, 'mac_address': _mac_addr, 'mtu': _mtu})
for interface in nb.virtualization.interfaces.filter(virtual_machine_id=netbox_vm.id):
- _ntb_if.append({'name': interface.name, 'mac_address': interface.mac_address, 'mtu': interface.mtu})
+ _ntb_if.append({'name': interface.name, 'mac_address': interface.mac_address.upper(), 'mtu': interface.mtu})
for pmx_if_mac in [_if['mac_address'] for _if in _pmx_if]:
pmx_if = next((_if for _if in _pmx_if if _if['mac_address'] == pmx_if_mac), None)
From 7a426e7e2b324f78fa21fb1b1d7898bb86043462 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 12:55:17 +0000
Subject: [PATCH 066/313] Add try-except and other if to check cluster name
---
netbox_proxbox/proxbox_api/updates/node.py | 44 ++++++++++++----------
1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index 788931a..b9d07a3 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -59,9 +59,26 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
#
# Compare CLUSTER
#
- if proxmox_cluster != None:
- # If cluster is filled, but different from actual cluster, update it.
- if netbox_node.cluster.name != proxmox_cluster['name']:
+ try:
+ if proxmox_cluster != None and netbox_node != None:
+ # If cluster is not filled or even filled, but different from actual cluster, update it.
+ if netbox_node.cluster.name != proxmox_cluster['name'] or netbox_node.cluster.name == None:
+ # Search for Proxmox Cluster using create.cluster() function
+ cluster_id = create.virtualization.cluster().id
+
+ # Use Cluster ID to update NODE information
+ netbox_node.cluster.id = cluster_id
+
+ if netbox_node.save() == True:
+ cluster_updated = True
+ else:
+ cluster_updated = False
+
+ else:
+ cluster_updated = False
+
+ # If cluster is empty, update it.
+ elif proxmox_cluster == None:
# Search for Proxmox Cluster using create.cluster() function
cluster_id = create.virtualization.cluster().id
@@ -72,26 +89,15 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
cluster_updated = True
else:
cluster_updated = False
-
+
+ # If cluster was not empty and also not different, do not make any change.
else:
cluster_updated = False
+
+ except Exception as error:
+ print(f"[ERROR] {error}")
- # If cluster is empty, update it.
- elif proxmox_cluster == None:
- # Search for Proxmox Cluster using create.cluster() function
- cluster_id = create.virtualization.cluster().id
-
- # Use Cluster ID to update NODE information
- netbox_node.cluster.id = cluster_id
- if netbox_node.save() == True:
- cluster_updated = True
- else:
- cluster_updated = False
-
- # If cluster was not empty and also not different, do not make any change.
- else:
- cluster_updated = False
return cluster_updated
From 29a818a2686568083cc0f6a2631fcdf5347d5da4 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 13:14:24 +0000
Subject: [PATCH 067/313] Declare 'cluster_updated' variable before try-except
---
netbox_proxbox/proxbox_api/updates/node.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index b9d07a3..6b48dc6 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -59,6 +59,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
#
# Compare CLUSTER
#
+ cluster_updated = False
try:
if proxmox_cluster != None and netbox_node != None:
# If cluster is not filled or even filled, but different from actual cluster, update it.
@@ -93,7 +94,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
# If cluster was not empty and also not different, do not make any change.
else:
cluster_updated = False
-
+
except Exception as error:
print(f"[ERROR] {error}")
From 719a10f3f9a64ead7b59d767e715484336eaa4ed Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 13:26:43 +0000
Subject: [PATCH 068/313] add more print to help debugging
---
netbox_proxbox/proxbox_api/updates/node.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index 6b48dc6..22c806f 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -60,6 +60,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
# Compare CLUSTER
#
cluster_updated = False
+
try:
if proxmox_cluster != None and netbox_node != None:
# If cluster is not filled or even filled, but different from actual cluster, update it.
@@ -96,7 +97,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
cluster_updated = False
except Exception as error:
- print(f"[ERROR] {error}")
+ print(f"[ERROR] {error}\n netbox_node: {netbox_node}\n> netbox_node.cluster.id: {netbox_node.cluster.id}\n> proxmox_cluster: {proxmox_cluster}")
From 6b71aa95d8900037d993c21f53147e0796d79e38 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 13:40:24 +0000
Subject: [PATCH 069/313] check if 'netbox_node' is None
---
netbox_proxbox/proxbox_api/updates/node.py | 54 +++++++++++-----------
1 file changed, 28 insertions(+), 26 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index 22c806f..0d57574 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -61,10 +61,27 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
#
cluster_updated = False
- try:
- if proxmox_cluster != None and netbox_node != None:
- # If cluster is not filled or even filled, but different from actual cluster, update it.
- if netbox_node.cluster.name != proxmox_cluster['name'] or netbox_node.cluster.name == None:
+ if netbox_node != None:
+ try:
+ if proxmox_cluster != None and netbox_node != None:
+ # If cluster is not filled or even filled, but different from actual cluster, update it.
+ if netbox_node.cluster.name != proxmox_cluster['name'] or netbox_node.cluster.name == None:
+ # Search for Proxmox Cluster using create.cluster() function
+ cluster_id = create.virtualization.cluster().id
+
+ # Use Cluster ID to update NODE information
+ netbox_node.cluster.id = cluster_id
+
+ if netbox_node.save() == True:
+ cluster_updated = True
+ else:
+ cluster_updated = False
+
+ else:
+ cluster_updated = False
+
+ # If cluster is empty, update it.
+ elif proxmox_cluster == None:
# Search for Proxmox Cluster using create.cluster() function
cluster_id = create.virtualization.cluster().id
@@ -75,31 +92,16 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
cluster_updated = True
else:
cluster_updated = False
-
- else:
- cluster_updated = False
-
- # If cluster is empty, update it.
- elif proxmox_cluster == None:
- # Search for Proxmox Cluster using create.cluster() function
- cluster_id = create.virtualization.cluster().id
-
- # Use Cluster ID to update NODE information
- netbox_node.cluster.id = cluster_id
-
- if netbox_node.save() == True:
- cluster_updated = True
+
+ # If cluster was not empty and also not different, do not make any change.
else:
cluster_updated = False
-
- # If cluster was not empty and also not different, do not make any change.
- else:
- cluster_updated = False
-
- except Exception as error:
- print(f"[ERROR] {error}\n netbox_node: {netbox_node}\n> netbox_node.cluster.id: {netbox_node.cluster.id}\n> proxmox_cluster: {proxmox_cluster}")
-
+ except Exception as error:
+ print(f"[ERROR] {error}\n netbox_node: {netbox_node}\n> netbox_node.cluster.id: {netbox_node.cluster.id}\n> proxmox_cluster: {proxmox_cluster}")
+ else:
+ print(f"netbox_node: {netbox_node}")
+ cluster_updated = False
return cluster_updated
From 10538769385327548132a74cbd7a118d438fd99b Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 13:48:15 +0000
Subject: [PATCH 070/313] add netbox_node print to help debugging
---
netbox_proxbox/proxbox_api/update.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 8a5275b..a8f40af 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -356,6 +356,7 @@ def nodes(**kwargs):
# Search netbox using VM name
netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
+ print(f"(1) netbox_search: {netbox_search}")
# Search node on Netbox with Proxmox node name gotten
if nb.dcim.devices.get(name = proxmox_node_name) == None:
@@ -391,6 +392,7 @@ def nodes(**kwargs):
else:
# If node already exist, try updating it.
netbox_node = netbox_search
+ print(f"(1) netbox_node: {netbox_node}")
# Update Netbox node information, if necessary.
full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
From 15b350333c83ce7befb30e1ac55f51f1ecd246d7 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 13:58:49 +0000
Subject: [PATCH 071/313] add more prints
---
netbox_proxbox/proxbox_api/update.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index a8f40af..6e2640f 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -393,6 +393,9 @@ def nodes(**kwargs):
# If node already exist, try updating it.
netbox_node = netbox_search
print(f"(1) netbox_node: {netbox_node}")
+ print(f"> netbox_node.id: {netbox_node.id}")
+ print(f"> netbox_node.cluster: {netbox_node.cluster}")
+ print(f"> netbox_node.cluster.id: {netbox_node.cluster.id}")
# Update Netbox node information, if necessary.
full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
From 67d389d373a1d2fea5e46a84fd2c95982c00be5c Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 14:08:34 +0000
Subject: [PATCH 072/313] remove prints as error was found, now I will work on
definitive solution
---
netbox_proxbox/proxbox_api/update.py | 5 -----
1 file changed, 5 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 6e2640f..8a5275b 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -356,7 +356,6 @@ def nodes(**kwargs):
# Search netbox using VM name
netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
- print(f"(1) netbox_search: {netbox_search}")
# Search node on Netbox with Proxmox node name gotten
if nb.dcim.devices.get(name = proxmox_node_name) == None:
@@ -392,10 +391,6 @@ def nodes(**kwargs):
else:
# If node already exist, try updating it.
netbox_node = netbox_search
- print(f"(1) netbox_node: {netbox_node}")
- print(f"> netbox_node.id: {netbox_node.id}")
- print(f"> netbox_node.cluster: {netbox_node.cluster}")
- print(f"> netbox_node.cluster.id: {netbox_node.cluster.id}")
# Update Netbox node information, if necessary.
full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
From 0c0e28139e711be5ea94326ee8d64d1f5d14a546 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 19:02:09 +0000
Subject: [PATCH 073/313] create device with '(2)' appended if it already
exists on Netbox
---
netbox_proxbox/proxbox_api/create/dcim.py | 5 ++
netbox_proxbox/proxbox_api/update.py | 85 +++++++++++++++++-----
netbox_proxbox/proxbox_api/updates/node.py | 5 +-
3 files changed, 75 insertions(+), 20 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index 6aad84b..8ee50cc 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -148,6 +148,11 @@ def node(proxmox_node):
node_json["status"] = 'active'
node_json["tags"] = [extras.tag().id]
node_json["cluster"] = virtualization.cluster().id
+
+ # If device already exists, append (2) to final of the name
+ check_duplicate = proxmox_node.get("duplicate", False)
+ if check_duplicate:
+ node_json["name"] = f"{proxmox_node['name']} (2)"
# Create Node with json 'node_json'
try:
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 8a5275b..4d25837 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -17,6 +17,8 @@
remove,
)
+from .create import extras
+
# Call all functions to update Virtual Machine
def vm_full_update(netbox_vm, proxmox_vm):
changes = {}
@@ -54,6 +56,9 @@ def vm_full_update(netbox_vm, proxmox_vm):
def node_full_update(netbox_node, proxmox_json, proxmox_cluster):
+ print(f"netbox_node: {netbox_node} | {type(netbox_node)}")
+ print(f"proxmox_json: {proxmox_json} | {type(proxmox_json)}")
+ print(f"proxmox_cluster: {proxmox_cluster} | {type(proxmox_cluster)}")
changes = {}
status_updated = updates.node.status(netbox_node, proxmox_json)
@@ -347,6 +352,7 @@ def virtual_machine(**kwargs):
def nodes(**kwargs):
+ print("\n\nNODES TESTE\n\n")
proxmox_cluster = kwargs.get('proxmox_cluster')
proxmox_json = kwargs.get('proxmox_json')
@@ -356,9 +362,9 @@ def nodes(**kwargs):
# Search netbox using VM name
netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
-
+ print(f"netbox_search: {netbox_search}")
# Search node on Netbox with Proxmox node name gotten
- if nb.dcim.devices.get(name = proxmox_node_name) == None:
+ if netbox_search == None:
# If node does not exist, create it.
netbox_node = create.dcim.node(proxmox_json)
@@ -389,25 +395,70 @@ def nodes(**kwargs):
json_node["result"] = False
else:
- # If node already exist, try updating it.
- netbox_node = netbox_search
+ print("device found")
+ try:
+ # Check if Proxbox tag exist.
+ print(netbox_search.tags)
- # Update Netbox node information, if necessary.
- full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
- json_node = full_update
+ search_tag = netbox_search.tags.index(extras.tag())
+ print(f"search_tag: {search_tag}")
- full_update_list = list(full_update.values())
+ # If node already exist, try updating it.
+ netbox_node = netbox_search
- # Analyze if update was successful
- if True in full_update_list:
- print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
- else:
- print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
+ # Update Netbox node information, if necessary.
+ full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
+ json_node = full_update
+
+ full_update_list = list(full_update.values())
+
+ # Analyze if update was successful
+ if True in full_update_list:
+ print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
+ else:
+ print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
- # return True as the node was successfully created.
- json_node["node_id"] = netbox_node.id
- json_node["name"] = proxmox_node_name
- json_node["result"] = True
+ # return True as the node was successfully created.
+ json_node["node_id"] = netbox_node.id
+ json_node["name"] = proxmox_node_name
+ json_node["result"] = True
+
+ except ValueError as error:
+ # Tag was not found within device, so there is already existing device.
+ print(f"[WARNING] Device with the same name as {netbox_search.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
+
+ proxmox_json["duplicate"] = True
+
+ # If node does not exist, create it.
+ netbox_node = create.dcim.node(proxmox_json)
+
+ # Node created
+ if netbox_node != None:
+ print("[OK] Node created! -> {}".format(proxmox_node_name))
+
+ # Update rest of configuration
+ full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
+ json_node = full_update
+
+ full_update_list = list(full_update.values())
+
+ # Analyze if update was successful
+ if True in full_update_list:
+ print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
+ else:
+ print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
+
+ # return True as the node was successfully created.
+ json_node["node_id"] = netbox_node.id
+ json_node["name"] = proxmox_node_name
+ json_node["result"] = True
+
+ # Error with node creation
+ else:
+ print('[ERROR] Something went wrong when creating the node.-> {}'.format(proxmox_node_name))
+ json_node["result"] = False
+
+
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index 0d57574..deeae74 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -63,7 +63,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
if netbox_node != None:
try:
- if proxmox_cluster != None and netbox_node != None:
+ if proxmox_cluster != None:
# If cluster is not filled or even filled, but different from actual cluster, update it.
if netbox_node.cluster.name != proxmox_cluster['name'] or netbox_node.cluster.name == None:
# Search for Proxmox Cluster using create.cluster() function
@@ -98,9 +98,8 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
cluster_updated = False
except Exception as error:
- print(f"[ERROR] {error}\n netbox_node: {netbox_node}\n> netbox_node.cluster.id: {netbox_node.cluster.id}\n> proxmox_cluster: {proxmox_cluster}")
+ print(f"[ERROR] {error}")
else:
- print(f"netbox_node: {netbox_node}")
cluster_updated = False
return cluster_updated
From afc4572b6967123831c5f7f67a59214aebad75a2 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Mon, 20 Mar 2023 21:05:35 +0000
Subject: [PATCH 074/313] Add comment with information about the original
device which was duplicated and fix minor bugs
---
netbox_proxbox/proxbox_api/create/dcim.py | 18 +++++-
netbox_proxbox/proxbox_api/update.py | 78 ++++++++---------------
2 files changed, 45 insertions(+), 51 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index 8ee50cc..24f73f8 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -10,7 +10,8 @@
virtualization,
)
-
+from netbox.configuration import PLUGINS_CONFIG
+proxbox_user_cfg = PLUGINS_CONFIG
#
# dcim.manufacturers
@@ -154,9 +155,24 @@ def node(proxmox_node):
if check_duplicate:
node_json["name"] = f"{proxmox_node['name']} (2)"
+
+ original_device = proxmox_node.get("netbox_original_device", None)
+ if original_device:
+ print(f"proxbox_user_cfg: {proxbox_user_cfg}")
+ cfg = proxbox_user_cfg.get("netbox_proxbox").get("netbox")
+ domain = cfg.get("domain", 'netbox.example.com')
+ http_port = cfg.get("http_port", 80)
+ node_json["comments"] = f"The original device has the following info: **Device ID:** {original_device.id} **Name:** {original_device.name}"
+
+ #"configuration": configuration.PLUGINS_CONFIG,
+ #"default_config": ProxboxConfig.default_settings
+ #https://{{ configuration.netbox_proxbox.proxmox.domain }}:{{ configuration.netbox_proxbox.proxmox.http_port }}" target="_blank"
+
+ print(f"(node) node_json: {node_json}")
# Create Node with json 'node_json'
try:
netbox_obj = nb.dcim.devices.create(node_json)
+ print(f"netbox_obj: {netbox_obj}")
except:
print("[proxbox_api.create.node] Creation of NODE failed.")
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 4d25837..05eb54a 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -56,9 +56,6 @@ def vm_full_update(netbox_vm, proxmox_vm):
def node_full_update(netbox_node, proxmox_json, proxmox_cluster):
- print(f"netbox_node: {netbox_node} | {type(netbox_node)}")
- print(f"proxmox_json: {proxmox_json} | {type(proxmox_json)}")
- print(f"proxmox_cluster: {proxmox_cluster} | {type(proxmox_cluster)}")
changes = {}
status_updated = updates.node.status(netbox_node, proxmox_json)
@@ -352,19 +349,12 @@ def virtual_machine(**kwargs):
def nodes(**kwargs):
- print("\n\nNODES TESTE\n\n")
proxmox_cluster = kwargs.get('proxmox_cluster')
proxmox_json = kwargs.get('proxmox_json')
proxmox_node_name = proxmox_json.get("name")
- json_node = {}
-
- # Search netbox using VM name
- netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
- print(f"netbox_search: {netbox_search}")
- # Search node on Netbox with Proxmox node name gotten
- if netbox_search == None:
+ def create_node():
# If node does not exist, create it.
netbox_node = create.dcim.node(proxmox_json)
@@ -375,6 +365,8 @@ def nodes(**kwargs):
# Update rest of configuration
full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
json_node = full_update
+ json_node["result"] = True
+ json_node["node_id"] = netbox_node.id
full_update_list = list(full_update.values())
@@ -383,25 +375,39 @@ def nodes(**kwargs):
print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
else:
print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
+
+ return json_node
+
+ # Error with node creation
+ else:
+ print('[ERROR] Something went wrong when creating the node.-> {}'.format(proxmox_node_name))
+ json_node = {}
+ json_node["result"] = False
+
+ return json_node
+
+ # Search netbox using VM name
+ netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
+ # Search node on Netbox with Proxmox node name gotten
+ if netbox_search == None:
+ # If node does not exist, create it.
+ json_node = create_node()
+
+ # Node created
+ if json_node != None:
# return True as the node was successfully created.
- json_node["node_id"] = netbox_node.id
json_node["name"] = proxmox_node_name
- json_node["result"] = True
-
+
# Error with node creation
else:
print('[ERROR] Something went wrong when creating the node.-> {}'.format(proxmox_node_name))
json_node["result"] = False
else:
- print("device found")
try:
# Check if Proxbox tag exist.
- print(netbox_search.tags)
-
search_tag = netbox_search.tags.index(extras.tag())
- print(f"search_tag: {search_tag}")
# If node already exist, try updating it.
netbox_node = netbox_search
@@ -428,39 +434,11 @@ def nodes(**kwargs):
print(f"[WARNING] Device with the same name as {netbox_search.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
proxmox_json["duplicate"] = True
-
- # If node does not exist, create it.
- netbox_node = create.dcim.node(proxmox_json)
-
- # Node created
- if netbox_node != None:
- print("[OK] Node created! -> {}".format(proxmox_node_name))
-
- # Update rest of configuration
- full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
- json_node = full_update
-
- full_update_list = list(full_update.values())
-
- # Analyze if update was successful
- if True in full_update_list:
- print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
- else:
- print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
-
- # return True as the node was successfully created.
- json_node["node_id"] = netbox_node.id
- json_node["name"] = proxmox_node_name
- json_node["result"] = True
-
- # Error with node creation
- else:
- print('[ERROR] Something went wrong when creating the node.-> {}'.format(proxmox_node_name))
- json_node["result"] = False
-
-
-
+ proxmox_json["netbox_original_device"] = netbox_search
+ json_node = create_node()
+ # return True as the node was successfully created.
+ json_node["name"] = proxmox_node_name
return json_node
From 40013891725852e568e6318a5563d4b6f9de78eb Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Tue, 21 Mar 2023 17:20:05 +0000
Subject: [PATCH 075/313] Add 'Show JSON result' button on botton of page to
show raw json result
---
.../proxmox_vm_full_update.html | 25 +++++++++++++++++--
netbox_proxbox/views.py | 16 ++++++++++--
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
index 7d8ba28..776fbc0 100755
--- a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
+++ b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
@@ -24,9 +24,13 @@ Nodes
-
+ {% if node.node_id %}
+
+ {{ node.name }}
+
+ {% else %}
{{ node.name }}
-
+ {% endif %}
@@ -180,6 +184,23 @@ Virtual Machines and Containers
+
+
+
+ Show JSON result
+
+
+
+
+
+
+
+
+
{% endblock %}
{% block footer_links %}
diff --git a/netbox_proxbox/views.py b/netbox_proxbox/views.py
index a3bc8fc..5569e9c 100755
--- a/netbox_proxbox/views.py
+++ b/netbox_proxbox/views.py
@@ -3,7 +3,9 @@
# 'View' is a django subclass. Basic type of class-based views
from django.views import View
from django.views.generic.edit import CreateView, DeleteView, UpdateView
-from django_tables2 import RequestConfig
+
+from django.views.decorators.cache import never_cache
+
# Enables permissions for views using Django authentication system.
# PermissionRequiredMixin = will handle permission checks logic and will plug into the
# Netbox's existing authorization system.
@@ -23,6 +25,7 @@
from . import ProxboxConfig
+
class HomeView(View):
"""Homepage"""
template_name = 'netbox_proxbox/home.html'
@@ -75,22 +78,31 @@ def table_data():
return [virtualmachines_table, nodes_table]
'''
+
class ProxmoxFullUpdate(PermissionRequiredMixin, View):
"""Full Update of Proxmox information on Netbox."""
# Define permission
permission_required = "netbox_proxbox.view_proxmoxvm"
+
+
+
# service incoming GET HTTP requests
# 'pk' value is passed to get() via URL defined in urls.py
def get(self, request):
"""Get request."""
+ json_result = proxbox_api.update.all(remove_unused = True)
+
+ import json
+
return render(
request,
"netbox_proxbox/proxmox_vm_full_update.html",
{
- "proxmox": proxbox_api.update.all(remove_unused = True),
+ "proxmox": json_result,
+ "proxmox_json": json.dumps(json_result, indent=4)
},
)
From f8b4118617baba54b7a0e95effb1368388f47c64 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Tue, 21 Mar 2023 18:43:23 +0000
Subject: [PATCH 076/313] Fix minor bugs related to creating duplicated device
---
netbox_proxbox/proxbox_api/create/dcim.py | 54 ++++++++++++-------
netbox_proxbox/proxbox_api/update.py | 6 ++-
.../proxmox_vm_full_update.html | 8 +--
3 files changed, 41 insertions(+), 27 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index 24f73f8..cac03be 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -10,9 +10,6 @@
virtualization,
)
-from netbox.configuration import PLUGINS_CONFIG
-proxbox_user_cfg = PLUGINS_CONFIG
-
#
# dcim.manufacturers
#
@@ -153,33 +150,52 @@ def node(proxmox_node):
# If device already exists, append (2) to final of the name
check_duplicate = proxmox_node.get("duplicate", False)
if check_duplicate:
+ # Redefine name appending (2) to final
node_json["name"] = f"{proxmox_node['name']} (2)"
original_device = proxmox_node.get("netbox_original_device", None)
if original_device:
- print(f"proxbox_user_cfg: {proxbox_user_cfg}")
- cfg = proxbox_user_cfg.get("netbox_proxbox").get("netbox")
- domain = cfg.get("domain", 'netbox.example.com')
- http_port = cfg.get("http_port", 80)
node_json["comments"] = f"The original device has the following info: **Device ID:** {original_device.id} **Name:** {original_device.name}"
- #"configuration": configuration.PLUGINS_CONFIG,
- #"default_config": ProxboxConfig.default_settings
- #https://{{ configuration.netbox_proxbox.proxmox.domain }}:{{ configuration.netbox_proxbox.proxmox.http_port }}" target="_blank"
-
- print(f"(node) node_json: {node_json}")
- # Create Node with json 'node_json'
- try:
- netbox_obj = nb.dcim.devices.create(node_json)
- print(f"netbox_obj: {netbox_obj}")
- except:
- print("[proxbox_api.create.node] Creation of NODE failed.")
+ print(f"(node) node_json: {node_json}")
netbox_obj = None
+ search_device = None
+
+ # Create Node with json 'node_json'
+ try:
+ # GET
+ search_device = nb.dcim.devices.get(
+ name = node_json["name"],
+ cluster = node_json["cluster"]
+ )
+ return search_device
+ except Exception as error:
+ print(error)
+
+ try:
+ # CREATE
+ if search_device == None:
+ netbox_obj = nb.dcim.devices.create(node_json)
+ return netbox_obj
+ except Exception as error:
+ print(error)
+
+ finally:
+ print("[proxbox_api.create.node] Creation of NODE failed.")
+ netbox_obj = None
+ # If NODE is not DUPLICATED, then CREATE it.
else:
- return netbox_obj
+ # Create Node with json 'node_json'
+ try:
+ netbox_obj = nb.dcim.devices.create(node_json)
+
+ except:
+ print("[proxbox_api.create.node] Creation of NODE failed.")
+ netbox_obj = None
+ return netbox_obj
# In case nothing works, returns error
netbox_obj = None
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 05eb54a..4febc62 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -356,6 +356,7 @@ def nodes(**kwargs):
def create_node():
# If node does not exist, create it.
+ print(f"proxmox_json: {proxmox_json}")
netbox_node = create.dcim.node(proxmox_json)
# Node created
@@ -380,7 +381,8 @@ def create_node():
# Error with node creation
else:
- print('[ERROR] Something went wrong when creating the node.-> {}'.format(proxmox_node_name))
+ print('netbox_node: ', netbox_node)
+ print('[ERROR] Something went wrong when creating the node.-> {} (2)'.format(proxmox_node_name))
json_node = {}
json_node["result"] = False
@@ -389,11 +391,13 @@ def create_node():
# Search netbox using VM name
netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
+ print(f"\nnetbox_search: {netbox_search}\n")
# Search node on Netbox with Proxmox node name gotten
if netbox_search == None:
# If node does not exist, create it.
json_node = create_node()
+ print(f"node created: {json_node}")
# Node created
if json_node != None:
# return True as the node was successfully created.
diff --git a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
index 776fbc0..275eb40 100755
--- a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
+++ b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
@@ -184,7 +184,7 @@ Virtual Machines and Containers
-
+
Show JSON result
@@ -195,12 +195,6 @@ Virtual Machines and Containers
{{ proxmox_json }}
-
-
-
-
-
-
{% endblock %}
{% block footer_links %}
From c650f379e1955cb700108b45dac7009f98cbefd4 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Tue, 21 Mar 2023 21:05:33 +0000
Subject: [PATCH 077/313] create device with '(2)' appended if it already
exists on Netbox
---
netbox_proxbox/proxbox_api/create/dcim.py | 16 +---
.../proxbox_api/create/virtualization.py | 23 ++---
netbox_proxbox/proxbox_api/update.py | 84 +++++++------------
.../proxmox_vm_full_update.html | 10 ++-
4 files changed, 54 insertions(+), 79 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index cac03be..b7e4bfb 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -33,7 +33,7 @@ def manufacturer():
description = proxbox_manufacturer_desc
)
except:
- return "Error creating the '{0}' manufacturer. Possible errors: the name '{0}' or slug '{1}' is already used.".format(proxbox_manufacturer_name, proxbox_manufacturer_slug)
+ return f"Error creating the '{proxbox_manufacturer_name}' manufacturer. Possible errors: the name '{proxbox_manufacturer_name}' or slug '{proxbox_manufacturer_slug}' is already used."
else:
manufacturer = proxbox_manufacturer
@@ -41,9 +41,6 @@ def manufacturer():
return manufacturer
-
-
-
#
# dcim.device_types
#
@@ -69,7 +66,7 @@ def device_type():
tags = [extras.tag().id]
)
except:
- return "Error creating the '{0}' device type. Possible errors: the model '{0}' or slug '{1}' is already used.".format(proxbox_device_type_model, proxbox_device_type_slug)
+ return f"Error creating the '{proxbox_device_type_model}' device type. Possible errors: the model '{proxbox_device_type_model}' or slug '{proxbox_device_type_slug}' is already used."
else:
device_type = proxbox_device_types
@@ -77,9 +74,6 @@ def device_type():
return device_type
-
-
-
#
# dcim.sites
#
@@ -117,7 +111,7 @@ def site(**kwargs):
tags = [extras.tag().id]
)
except:
- return "Error creating the '{0}' site. Possible errors: the name '{0}' or slug '{1}' is already used.".format(site_proxbox_name, site_proxbox_slug)
+ return f"Error creating the '{site_proxbox_name}' site. Possible errors: the name '{site_proxbox_name}' or slug '{site_proxbox_slug}' is already used."
# If basic site already created, use it.
else:
@@ -129,10 +123,6 @@ def site(**kwargs):
return site
-
-
-
-
#
# dcim.devices (nodes)
#
diff --git a/netbox_proxbox/proxbox_api/create/virtualization.py b/netbox_proxbox/proxbox_api/create/virtualization.py
index 4466bb7..cf74447 100755
--- a/netbox_proxbox/proxbox_api/create/virtualization.py
+++ b/netbox_proxbox/proxbox_api/create/virtualization.py
@@ -37,7 +37,7 @@ def cluster_type():
description = 'Proxmox Virtual Environment. Open-source server management platform'
)
except Exception as request_error:
- raise RuntimeError("Error creating the '{0}' cluster type.".format(cluster_type_name)) from request_error
+ raise RuntimeError(f"Error creating the '{cluster_type_name}' cluster type.") from request_error
else:
cluster_type = cluster_type_proxbox
@@ -79,7 +79,7 @@ def cluster():
tags = [extras.tag().id]
)
except:
- return "Error creating the '{0}' cluster. Possible errors: the name '{0}' is already used.".format(proxmox_cluster_name)
+ return f"Error creating the '{proxmox_cluster_name}' cluster. Possible errors: the name '{proxmox_cluster_name}' is already used."
else:
cluster = cluster_proxbox
@@ -97,17 +97,22 @@ def cluster():
#
# virtualization.virtual_machines
#
-def virtual_machine(proxmox_vm):
+def virtual_machine(proxmox_vm, duplicate):
# Create json with basic VM/CT information
vm_json = {}
+ netbox_obj = None
if proxmox_vm['status'] == 'running':
vm_json["status"] = 'active'
elif proxmox_vm == 'stopped':
vm_json["status"] = 'offline'
+ if duplicate:
+ print("VM/CT is duplicated")
+ vm_json["name"] = f"{proxmox_vm['name']} + (2)"
+ else:
+ vm_json["name"] = proxmox_vm['name']
- vm_json["name"] = proxmox_vm['name']
vm_json["status"] = 'active'
vm_json["cluster"] = cluster().id
vm_json["role"] = extras.role(role_id = NETBOX_VM_ROLE_ID).id
@@ -115,15 +120,13 @@ def virtual_machine(proxmox_vm):
# Create VM/CT with json 'vm_json'
try:
+ print(f"vm_json: {vm_json}")
netbox_obj = nb.virtualization.virtual_machines.create(vm_json)
+ return netbox_obj
except:
print("[proxbox.create.virtual_machine] Creation of VM/CT failed.")
netbox_obj = None
- else:
- return netbox_obj
-
- # In case nothing works, returns error
- netbox_obj = None
- return netbox_obj
\ No newline at end of file
+
+ return netbox_obj
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 4febc62..8b6e72b 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -71,22 +71,6 @@ def node_full_update(netbox_node, proxmox_json, proxmox_cluster):
return changes
-
-# Verify if VM/CT exist on Netbox
-def is_vm_on_netbox(netbox_vm):
- # Search VM on Netbox by using VM Name gotten from Proxmox
- # VM doesn't exist on Netbox
- if netbox_vm == None:
- vm_on_netbox = False
-
- # VM already exist on Netbox
- else:
- vm_on_netbox = True
-
- return vm_on_netbox
-
-
-
def search_by_proxmox_id(proxmox_id):
all_proxmox_vms = proxmox.cluster.resources.get(type='vm')
@@ -159,7 +143,7 @@ def virtual_machine(**kwargs):
if proxmox_id != None:
proxmox_id_type = type(proxmox_id)
if 'int' not in str(proxmox_id_type):
- print('[ERROR] "proxmox_id" MUST be integer. Type used: {}'.format(proxmox_id_type))
+ print(f'[ERROR] "proxmox_id" MUST be integer. Type used: {proxmox_id_type}')
#return False
json_vm["result"] = False
@@ -170,7 +154,7 @@ def virtual_machine(**kwargs):
if id != None:
id_type = type(id)
if 'int' not in str(id_type):
- print('[ERROR] "id" MUST be integer. Type used: {}'.format(id_type))
+ print(f'[ERROR] "id" MUST be integer. Type used: {id_type}')
#return False
json_vm["result"] = False
@@ -182,7 +166,7 @@ def virtual_machine(**kwargs):
if name != None:
name_type = type(name)
if 'str' not in str(name_type):
- print('[ERROR] "name" MUST be string. Type used: {}'.format(name_type))
+ print(f'[ERROR] "name" MUST be string. Type used: {name_type}')
#return False
json_vm["result"] = False
@@ -270,12 +254,18 @@ def virtual_machine(**kwargs):
# Search Netbox object by name gotten from Proxmox
netbox_vm = nb.virtualization.virtual_machines.get(name = proxmox_vm_name)
-
- # Analyze if VM exist on Netbox
- # If VM/CT already exist on Proxmox, check VM and update it, if necessary.
- vm_on_netbox = is_vm_on_netbox(netbox_vm)
-
- if vm_on_netbox == True:
+
+ duplicate = False
+ try:
+ # Check if Proxbox tag exist.
+ search_tag = netbox_vm.tags.index(extras.tag())
+ except Exception as error:
+ print(f"[WARNING] Virtual Machine or Container with the same name as {netbox_vm.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
+ netbox_vm = False
+ duplicate = True
+
+ # VM Found:
+ if netbox_vm:
# Update Netbox information
full_update = vm_full_update(netbox_vm, proxmox_json)
@@ -289,25 +279,23 @@ def virtual_machine(**kwargs):
json_vm["interfaces"] = full_update["interfaces"]
json_vm["ips"] = full_update["ips"]
-
full_update_list = list(full_update.values())
# Analyze if VM needed to be updated on Netbox
if True in full_update_list:
- print('[OK] VM updated. -> {}'.format(proxmox_vm_name))
+ print(f'[OK] VM updated. -> {proxmox_vm_name}')
else:
- print('[OK] VM already updated. -> {}'.format(proxmox_vm_name))
+ print(f'[OK] VM already updated. -> {proxmox_vm_name}')
# In case none of condition works, return True anyway, since VM already exist.
json_vm["result"] = True
# If VM does not exist, create it on Netbox
- elif vm_on_netbox == False:
- print('[OK] VM does not exist on Netbox -> {}'.format(proxmox_vm_name))
-
+ else:
+ print(f'[OK] VM does not exist on Netbox -> {proxmox_vm_name}')
# Analyze if VM was sucessfully created.
- netbox_vm = create.virtualization.virtual_machine(proxmox_json)
+ netbox_vm = create.virtualization.virtual_machine(proxmox_json, duplicate)
# VM created with basic information
if netbox_vm != None:
@@ -320,30 +308,24 @@ def virtual_machine(**kwargs):
# Analyze if update was successful
if True in full_update_list:
- print('[OK] VM created -> {}'.format(proxmox_vm_name))
+ print(f'[OK] VM created -> {netbox_vm.name}')
# VM fully updated
json_vm["result"] = True
else:
- print('[OK] VM created, but full update failed -> {}'.format(proxmox_vm_name))
+ print(f'[OK] VM created, but full update failed -> {proxmox_vm_name}')
# VM created with basic information
json_vm["result"] = True
else:
- print('[ERROR] VM not created. -> {}'.format(proxmox_vm_name))
+ print(f'[ERROR] VM not created. -> {proxmox_vm_name}')
# VM not created
json_vm["result"] = False
- else:
- print("[ERROR] Unexpected error -> {}".format(proxmox_vm_name))
-
- # Unexpected error
- json_vm["result"] = False
-
return json_vm
@@ -356,12 +338,11 @@ def nodes(**kwargs):
def create_node():
# If node does not exist, create it.
- print(f"proxmox_json: {proxmox_json}")
netbox_node = create.dcim.node(proxmox_json)
# Node created
if netbox_node != None:
- print("[OK] Node created! -> {}".format(proxmox_node_name))
+ print(f"[OK] Node created! -> {proxmox_node_name}")
# Update rest of configuration
full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
@@ -373,16 +354,15 @@ def create_node():
# Analyze if update was successful
if True in full_update_list:
- print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
+ print(f'[OK] NODE updated. -> {proxmox_node_name}')
else:
- print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
+ print(f'[OK] NODE already updated. -> {proxmox_node_name}')
return json_node
# Error with node creation
else:
- print('netbox_node: ', netbox_node)
- print('[ERROR] Something went wrong when creating the node.-> {} (2)'.format(proxmox_node_name))
+ print(f'[ERROR] Something went wrong when creating the node.-> {proxmox_node_name} (2)')
json_node = {}
json_node["result"] = False
@@ -391,13 +371,11 @@ def create_node():
# Search netbox using VM name
netbox_search = nb.dcim.devices.get(name = proxmox_node_name)
- print(f"\nnetbox_search: {netbox_search}\n")
# Search node on Netbox with Proxmox node name gotten
if netbox_search == None:
# If node does not exist, create it.
json_node = create_node()
- print(f"node created: {json_node}")
# Node created
if json_node != None:
# return True as the node was successfully created.
@@ -405,7 +383,7 @@ def create_node():
# Error with node creation
else:
- print('[ERROR] Something went wrong when creating the node.-> {}'.format(proxmox_node_name))
+ print(f'[ERROR] Something went wrong when creating the node.-> {proxmox_node_name}')
json_node["result"] = False
else:
@@ -424,9 +402,9 @@ def create_node():
# Analyze if update was successful
if True in full_update_list:
- print('[OK] NODE updated. -> {}'.format(proxmox_node_name))
+ print(f'[OK] NODE updated. -> {proxmox_node_name}')
else:
- print('[OK] NODE already updated. -> {}'.format(proxmox_node_name))
+ print(f'[OK] NODE already updated. -> {proxmox_node_name}')
# return True as the node was successfully created.
json_node["node_id"] = netbox_node.id
@@ -458,7 +436,7 @@ def all(**kwargs):
#
cluster = create.virtualization.cluster()
print('\n\n\nCLUSTER...')
- print('[OK] CLUSTER created. -> {}'.format(cluster.name))
+ print(f'[OK] CLUSTER created. -> {cluster.name}')
proxmox_cluster = cluster_all[0]
#
diff --git a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
index 275eb40..21a8cb1 100755
--- a/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
+++ b/netbox_proxbox/templates/netbox_proxbox/proxmox_vm_full_update.html
@@ -103,16 +103,20 @@ Virtual Machines and Containers
-
+ {% if virtualmachine.vm_id %}
+
+ {{ virtualmachine.name }}
+
+ {% else %}
{{ virtualmachine.name }}
-
+ {% endif %}
{% if virtualmachine.status %}
{{ virtualmachine.status }}
-
+
{% else %}
{{ virtualmachine.status }}
From b3900a33af239cd0e71b91e49149240e2a53a96c Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Wed, 22 Mar 2023 14:02:11 +0000
Subject: [PATCH 078/313] Add 'show configuration' to view raw config and link
to examples
---
netbox_proxbox/proxbox_api/create/extras.py | 4 +-
.../proxbox_api/create/virtualization.py | 2 +-
.../templates/netbox_proxbox/home.html | 85 ++++++++++++++++---
netbox_proxbox/views.py | 14 +--
4 files changed, 86 insertions(+), 19 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/extras.py b/netbox_proxbox/proxbox_api/create/extras.py
index 67da512..963c86f 100755
--- a/netbox_proxbox/proxbox_api/create/extras.py
+++ b/netbox_proxbox/proxbox_api/create/extras.py
@@ -26,7 +26,7 @@ def tag():
description = "Proxbox Identifier (used to identify the items the plugin created)"
)
except:
- return "Error creating the '{0}' tag. Possible errors: the name '{0}' or slug '{1}' is already used.".format(proxbox_tag_name, proxbox_tag_slug)
+ return f"Error creating the '{proxbox_tag_name}' tag. Possible errors: the name '{proxbox_tag_name}' or slug '{proxbox_tag_slug}' is already used."
else:
tag = proxbox_tag
@@ -75,7 +75,7 @@ def role(**kwargs):
vm_role = True
)
except:
- return "Error creating the '{0}' role. Possible errors: the name '{0}' or slug '{1}' is already used.".format(role_proxbox_name, role_proxbox_slug)
+ return f"Error creating the '{role_proxbox_name}' role. Possible errors: the name '{role_proxbox_name}' or slug '{role_proxbox_slug}' is already used."
# If basic role already created, use it.
else:
diff --git a/netbox_proxbox/proxbox_api/create/virtualization.py b/netbox_proxbox/proxbox_api/create/virtualization.py
index cf74447..ea9cb7a 100755
--- a/netbox_proxbox/proxbox_api/create/virtualization.py
+++ b/netbox_proxbox/proxbox_api/create/virtualization.py
@@ -109,7 +109,7 @@ def virtual_machine(proxmox_vm, duplicate):
if duplicate:
print("VM/CT is duplicated")
- vm_json["name"] = f"{proxmox_vm['name']} + (2)"
+ vm_json["name"] = f"{proxmox_vm['name']} (2)"
else:
vm_json["name"] = proxmox_vm['name']
diff --git a/netbox_proxbox/templates/netbox_proxbox/home.html b/netbox_proxbox/templates/netbox_proxbox/home.html
index 804e397..1602cab 100644
--- a/netbox_proxbox/templates/netbox_proxbox/home.html
+++ b/netbox_proxbox/templates/netbox_proxbox/home.html
@@ -2,8 +2,6 @@
{% load static %}
{% block content %}
-
-
{# Full Update Button#}
@@ -32,7 +30,7 @@
- Domain / IP
+ Domain / IP
{% if configuration.netbox_proxbox.proxmox.domain %}
{{ configuration.netbox_proxbox.proxmox.domain }}
{% else %}
@@ -69,7 +67,7 @@
{% else %}
{{ default_config.proxmox.token.name }} (default)
{% endif %}
-
+
Token Value
{% if configuration.netbox_proxbox.proxmox.token.value %}
{{ configuration.netbox_proxbox.proxmox.token.value }}
@@ -77,7 +75,7 @@
{{ default_config.proxmox.token.value }} (default)
{% endif %}
-
+
SSL
{% if configuration.netbox_proxbox.proxmox.ssl %}
{{ configuration.netbox_proxbox.proxmox.ssl }}
@@ -85,6 +83,18 @@
{{ default_config.proxmox.ssl }} (default)
{% endif %}
+
+ PLUGINS_CONFIG (example)
+
+
+ Click Here to View!
+
+
+
@@ -99,7 +109,7 @@
-
+
Domain / IP
{% if configuration.netbox_proxbox.netbox.domain %}
{{ configuration.netbox_proxbox.netbox.domain }}
@@ -107,7 +117,7 @@
{{ default_config.netbox.domain }} (default)
{% endif %}
-
+
HTTP Port
{% if configuration.netbox_proxbox.netbox.http_port %}
{{ configuration.netbox_proxbox.netbox.http_port }}
@@ -115,14 +125,14 @@
{{ default_config.netbox.http_port }} (default)
{% endif %}
-
+
Token
{% if configuration.netbox_proxbox.netbox.token %}
{{ configuration.netbox_proxbox.netbox.token }}
{% else %}
{{ default_config.netbox.token }} (default)
{% endif %}
-
+
SSL
{% if configuration.netbox_proxbox.netbox.ssl %}
@@ -131,12 +141,67 @@
{{ default_config.netbox.ssl }} (default)
{% endif %}
+
+ ProxboxConfig Class
+
+
+ Click Here to View
+
+
+
+
+
+
+
+
+
+
+
+ Show configuration
+
+
+
-
{% endblock %}
{% block footer_links %}
diff --git a/netbox_proxbox/views.py b/netbox_proxbox/views.py
index 5569e9c..4ed893c 100755
--- a/netbox_proxbox/views.py
+++ b/netbox_proxbox/views.py
@@ -24,8 +24,6 @@
from . import ProxboxConfig
-
-
class HomeView(View):
"""Homepage"""
template_name = 'netbox_proxbox/home.html'
@@ -33,12 +31,18 @@ class HomeView(View):
# service incoming GET HTTP requests
def get(self, request):
"""Get request."""
+
+ plugin_configuration = configuration.PLUGINS_CONFIG
+ default_config = ProxboxConfig.default_settings
+
return render(
request,
self.template_name,
{
- "configuration": configuration.PLUGINS_CONFIG,
- "default_config": ProxboxConfig.default_settings
+ "configuration": plugin_configuration,
+ "default_config": default_config,
+ "configuration_json": json.dumps(plugin_configuration, indent=4),
+ "default_config_json": json.dumps(default_config, indent=4)
}
)
@@ -95,8 +99,6 @@ def get(self, request):
json_result = proxbox_api.update.all(remove_unused = True)
- import json
-
return render(
request,
"netbox_proxbox/proxmox_vm_full_update.html",
From 1c179ae0e81eaa942959f10a62eb2eaf21b03112 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Wed, 22 Mar 2023 14:18:05 +0000
Subject: [PATCH 079/313] transform example links into buttons
---
.../templates/netbox_proxbox/home.html | 43 ++++++++-----------
1 file changed, 18 insertions(+), 25 deletions(-)
diff --git a/netbox_proxbox/templates/netbox_proxbox/home.html b/netbox_proxbox/templates/netbox_proxbox/home.html
index 1602cab..88892f9 100644
--- a/netbox_proxbox/templates/netbox_proxbox/home.html
+++ b/netbox_proxbox/templates/netbox_proxbox/home.html
@@ -83,19 +83,16 @@
{{ default_config.proxmox.ssl }} (default)
{% endif %}
-
- PLUGINS_CONFIG (example)
-
-
- Click Here to View!
-
-
-
+
@@ -141,20 +138,16 @@
{{ default_config.netbox.ssl }} (default)
{% endif %}
-
- ProxboxConfig Class
-
-
- Click Here to View
-
-
-
-
+
From 4aba25cad0a3d840b2aa261bd702c6599eb4409d Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Wed, 22 Mar 2023 14:38:39 +0000
Subject: [PATCH 080/313] minor changes
---
netbox_proxbox/templates/netbox_proxbox/home.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/netbox_proxbox/templates/netbox_proxbox/home.html b/netbox_proxbox/templates/netbox_proxbox/home.html
index 88892f9..8e95eb1 100644
--- a/netbox_proxbox/templates/netbox_proxbox/home.html
+++ b/netbox_proxbox/templates/netbox_proxbox/home.html
@@ -155,7 +155,7 @@
- Show configuration
+ Show configuration (JSON)
From f7e22f83013fc3d7716920a96e14bb6a1b8750b1 Mon Sep 17 00:00:00 2001
From: JEAN-FRANCOIS GUILLAUME
Date: Wed, 22 Mar 2023 17:11:08 +0100
Subject: [PATCH 081/313] correcting missing mtu and wrong identifier
---
netbox_proxbox/proxbox_api/updates/node.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index 6b48dc6..bd18003 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -108,7 +108,7 @@ def interfaces(netbox_node, proxmox_json):
_lag_port = ['OVSBond']
_brg_port = ['OVSBridge']
_pmx_iface = []
- _ntb_iface = [{'name': iface.name, 'mtu' : int(iface.mtu), 'tagged_vlans': [int(x['vid']) for x in iface.tagged_vlans]} for iface in nb.dcim.interfaces.filter(device_id=netbox_node.id)]
+ _ntb_iface = [{'name': iface.name, 'mtu' : int(iface.mtu) if iface.mtu else 1500, 'tagged_vlans': [int(x['vid']) for x in iface.tagged_vlans]} for iface in nb.dcim.interfaces.filter(device_id=netbox_node.id)]
_eth = [iface for iface in proxmox.nodes(proxmox_json['name']).network.get() if iface['type'] == 'eth']
_virt = [iface for iface in proxmox.nodes(proxmox_json['name']).network.get() if iface['type'] in _int_port]
_bond = [iface for iface in proxmox.nodes(proxmox_json['name']).network.get() if iface['type'] in _lag_port]
@@ -223,8 +223,9 @@ def interfaces(netbox_node, proxmox_json):
for iface in [x.get('name') for x in _ntb_iface]:
if iface not in [x.get('name') for x in _pmx_iface]:
- ntb_iface = list(nb.dcim.interfaces.filter(device_id=netbox_node.id, name=iface['name']))
+ ntb_iface = list(nb.dcim.interfaces.filter(device_id=netbox_node.id, name=iface))
if len(ntb_iface) == 1:
- ntb_iface[0].delete()
+ if not ntb_iface[0].mgmt_only:
+ ntb_iface[0].delete()
return updated
From fc370ed4341bb5a02e71e0735dacb4289a2d9c6a Mon Sep 17 00:00:00 2001
From: JEAN-FRANCOIS GUILLAUME
Date: Thu, 23 Mar 2023 10:01:28 +0100
Subject: [PATCH 082/313] adding custom field to keep interface
---
README.md | 10 ++++++++++
netbox_proxbox/proxbox_api/updates/node.py | 2 +-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 22ebd00..c422af3 100755
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ The following table shows the Netbox and Proxmox versions compatible (tested) wi
- [3.1.1. Proxmox ID](#311-proxmox-id)
- [3.1.2. Proxmox Node](#312-proxmox-node)
- [3.1.3. Proxmox Type](#313-proxmox-type-qemu-or-lxc)
+ - [3.1.4. Proxmox Keep Interface](#314-proxmox-keep-interface)
- [3.2. Custom Field Example](#32-custom-field-example)
[4. Usage](#4-usage)
@@ -277,6 +278,15 @@ Optional values (may be different)
+#### 3.1.4. Proxmox Keep Interface
+
+Required values (must be equal)
+- [Custom Field] **Type:** Boolean (true/false)
+- [Custom Field] **Name:** proxmox_keep_interface
+- [Assignment] **Content-type:** DCIM > Interface
+
+
+
### 3.2. Custom Field Example
![custom field image](etc/img/custom_field_example.png?raw=true "preview")
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index bd18003..99b1e61 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -225,7 +225,7 @@ def interfaces(netbox_node, proxmox_json):
if iface not in [x.get('name') for x in _pmx_iface]:
ntb_iface = list(nb.dcim.interfaces.filter(device_id=netbox_node.id, name=iface))
if len(ntb_iface) == 1:
- if not ntb_iface[0].mgmt_only:
+ if not ntb_iface[0].mgmt_only or not ntb_iface[0].custom_fields.get('proxmox_keep_interface', False):
ntb_iface[0].delete()
return updated
From 8adc2a198ff0195038d4412b68652f20f2a41013 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Thu, 23 Mar 2023 15:23:14 +0000
Subject: [PATCH 083/313] create cluster with '(2)' appended if it already
exists on Netbox
---
netbox_proxbox/proxbox_api/create/dcim.py | 8 ++-
.../proxbox_api/create/virtualization.py | 68 ++++++++++++++++---
netbox_proxbox/proxbox_api/remove.py | 23 +++----
netbox_proxbox/proxbox_api/update.py | 13 ++--
4 files changed, 83 insertions(+), 29 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index b7e4bfb..c3105f7 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -135,7 +135,11 @@ def node(proxmox_node):
node_json["site"] = site(site_id = NETBOX_SITE_ID).id
node_json["status"] = 'active'
node_json["tags"] = [extras.tag().id]
- node_json["cluster"] = virtualization.cluster().id
+
+ cluster = virtualization.cluster()
+ if cluster:
+ if cluster != None:
+ node_json["cluster"] = cluster.id
# If device already exists, append (2) to final of the name
check_duplicate = proxmox_node.get("duplicate", False)
@@ -148,8 +152,6 @@ def node(proxmox_node):
if original_device:
node_json["comments"] = f"The original device has the following info: **Device ID:** {original_device.id} **Name:** {original_device.name}"
-
- print(f"(node) node_json: {node_json}")
netbox_obj = None
search_device = None
diff --git a/netbox_proxbox/proxbox_api/create/virtualization.py b/netbox_proxbox/proxbox_api/create/virtualization.py
index ea9cb7a..08b2e2e 100755
--- a/netbox_proxbox/proxbox_api/create/virtualization.py
+++ b/netbox_proxbox/proxbox_api/create/virtualization.py
@@ -63,13 +63,52 @@ def cluster():
# Verify if there any cluster created with:
# Name equal to Proxmox's Cluster name
# Cluster type equal to 'proxmox'
- cluster_proxbox = nb.virtualization.clusters.get(
- name = proxmox_cluster_name,
- type = cluster_type().slug
- )
+ try:
+ cluster_proxbox = nb.virtualization.clusters.get(
+ name = proxmox_cluster_name,
+ type = cluster_type().slug
+ )
+ except ValueError as error:
+ print(f"[ERROR] More than one cluster is created with the name '{proxmox_cluster_name}', making proxbox to abort update.\n > {error}")
+ return
+
+ nb_cluster_name = None
+ try:
+ if cluster_proxbox != None:
+ nb_cluster_name = cluster_proxbox.name
+ except Exception as error:
+ print(f"[ERROR] {error}")
- # If no 'cluster' found, create one using the name from Proxmox
- if cluster_proxbox == None:
+ duplicate = False
+ try:
+ # Check if Proxbox tag exist.
+ if cluster_proxbox != None:
+ search_tag = cluster_proxbox.tags.index(extras.tag())
+ except ValueError as error:
+ print(f"[WARNING] Cluster with the same name as {nb_cluster_name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
+ cluster_proxbox = False
+ duplicate = True
+
+ # If 'cluster' is found, check for duplicated and create another one, if necessary:
+ if cluster_proxbox != None:
+ # Check if it is duplicated:
+ if duplicate == True:
+ proxmox_cluster_name = f"{proxmox_cluster_name} (2)"
+
+ # Check if duplicated device was already created.
+ try:
+ print(proxmox_cluster_name)
+ search_device = nb.virtualization.clusters.get(
+ name = proxmox_cluster_name
+ )
+
+ if search_device != None:
+ return search_device
+
+ except Exception as error:
+ print(f"[ERROR] {error}")
+ else:
+ return cluster_proxbox
try:
# Create the cluster with only name and cluster_type
@@ -78,14 +117,24 @@ def cluster():
type = cluster_type().id,
tags = [extras.tag().id]
)
+ return cluster
except:
return f"Error creating the '{proxmox_cluster_name}' cluster. Possible errors: the name '{proxmox_cluster_name}' is already used."
-
+
+ # If no Cluster is found, create one.
else:
- cluster = cluster_proxbox
+ try:
+ # Create the cluster with only name and cluster_type
+ cluster = nb.virtualization.clusters.create(
+ name = proxmox_cluster_name,
+ type = cluster_type().id,
+ tags = [extras.tag().id]
+ )
+ return cluster
+ except:
+ return f"Error creating the '{proxmox_cluster_name}' cluster. Possible errors: the name '{proxmox_cluster_name}' is already used."
- return cluster
@@ -120,7 +169,6 @@ def virtual_machine(proxmox_vm, duplicate):
# Create VM/CT with json 'vm_json'
try:
- print(f"vm_json: {vm_json}")
netbox_obj = nb.virtualization.virtual_machines.create(vm_json)
return netbox_obj
diff --git a/netbox_proxbox/proxbox_api/remove.py b/netbox_proxbox/proxbox_api/remove.py
index 1df7a7d..bf21ce1 100755
--- a/netbox_proxbox/proxbox_api/remove.py
+++ b/netbox_proxbox/proxbox_api/remove.py
@@ -19,7 +19,7 @@ def is_vm_on_proxmox(netbox_vm):
# Analyze local_context of VM
if local_context == None:
- print('[WARNING] "local_context_data" not filled. -> {}'.format(netbox_name))
+ print(f'[WARNING] "local_context_data" not filled. -> {netbox_name}')
else:
# "proxmox" key of "local_context_data"
@@ -27,7 +27,7 @@ def is_vm_on_proxmox(netbox_vm):
# If null value, returns error
if proxmox_json == None:
- print("[WARNING] 'local_context_data' does not have 'proxmox' json key -> {}".format(netbox_name))
+ print(f"[WARNING] 'local_context_data' does not have 'proxmox' json key -> {netbox_name}")
else:
# Netbox VM/CT ID
@@ -35,7 +35,7 @@ def is_vm_on_proxmox(netbox_vm):
# If null value, returns error
if netbox_id == None:
- print("[WARNING] 'proxmox' doest not have 'id' key -> {}".format(netbox_name))
+ print(f"[WARNING] 'proxmox' doest not have 'id' key -> {netbox_name}")
# List names of VM/CT's from Proxmox
@@ -73,14 +73,14 @@ def is_vm_on_proxmox(netbox_vm):
local_context = netbox_vm.local_context_data
if local_context != None:
- print("[OK] 'local_context' updated' -> {}".format(netbox_name))
+ print(f"[OK] 'local_context' updated' -> {netbox_name}")
proxmox_json = local_context.get("proxmox")
netbox_id = proxmox_json.get("id")
else:
- print("[ERROR] 'local_context' is empty -> {}".format(netbox_name))
+ print(f"[ERROR] 'local_context' is empty -> {netbox_name}")
else:
- print("[WARNING] 'local_context' was not updated (error or already updated) -> {}".format(netbox_name))
+ print(f"[WARNING] 'local_context' was not updated (error or already updated) -> {netbox_name}")
# Search VM on Proxmox by using ID
@@ -97,7 +97,7 @@ def is_vm_on_proxmox(netbox_vm):
if id_on_px == True:
return True
else:
- print("[WARNING] NAME exists on Proxmox, but ID does not. -> {}".format(netbox_name))
+ print(f"[WARNING] NAME exists on Proxmox, but ID does not. -> {netbox_name}")
return True
# Comparison failed, not able to find VM on Proxmox
@@ -121,7 +121,7 @@ def all():
vm_on_proxmox = is_vm_on_proxmox(nb_vm_each)
if vm_on_proxmox == True:
- log_message = '[OK] VM exists on both systems (Netbox and Proxmox) -> {}'.format(netbox_name)
+ log_message = f'[OK] VM exists on both systems (Netbox and Proxmox) -> {netbox_name}'
print(log_message)
log.append(log_message)
@@ -129,7 +129,7 @@ def all():
# If VM does not exist on Proxmox, delete VM on Netbox.
elif vm_on_proxmox == False:
- log_message = "[WARNING] VM exists on Netbox, but not on Proxmox. Delete it! -> {}".format(netbox_name)
+ log_message = f"[WARNING] VM exists on Netbox, but not on Proxmox. Delete it! -> {netbox_name}"
print(log_message)
log.append(log_message)
@@ -147,12 +147,12 @@ def all():
delete_vm = netbox_obj.delete()
else:
- log_message = "[ERROR] VM will not be removed because the 'Proxbox' tag was not found. -> {}".format(netbox_name)
+ log_message = f"[ERROR] VM will not be removed because the 'Proxbox' tag was not found. -> {netbox_name}"
print(log_message)
log.append(log_message)
elif len(netbox_obj.tags) == 0:
- log_message = "[ERROR] VM will not be removed because the 'Proxbox' tag was not found. There is no tag configured.-> {}".format(netbox_name)
+ log_message = f"[ERROR] VM will not be removed because the 'Proxbox' tag was not found. There is no tag configured.-> {netbox_name}"
print(log_message)
log.append(log_message)
@@ -175,7 +175,6 @@ def all():
json_vm_all.append(json_vm)
- print(f"json_vm: {json_vm}")
return json_vm_all
\ No newline at end of file
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 8b6e72b..a8466d1 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -258,8 +258,9 @@ def virtual_machine(**kwargs):
duplicate = False
try:
# Check if Proxbox tag exist.
- search_tag = netbox_vm.tags.index(extras.tag())
- except Exception as error:
+ if netbox_vm != None:
+ search_tag = netbox_vm.tags.index(extras.tag())
+ except ValueError as error:
print(f"[WARNING] Virtual Machine or Container with the same name as {netbox_vm.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
netbox_vm = False
duplicate = True
@@ -411,7 +412,7 @@ def create_node():
json_node["name"] = proxmox_node_name
json_node["result"] = True
- except ValueError as error:
+ except Exception as error:
# Tag was not found within device, so there is already existing device.
print(f"[WARNING] Device with the same name as {netbox_search.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
@@ -436,7 +437,11 @@ def all(**kwargs):
#
cluster = create.virtualization.cluster()
print('\n\n\nCLUSTER...')
- print(f'[OK] CLUSTER created. -> {cluster.name}')
+
+ try:
+ print(f'[OK] CLUSTER created. -> {cluster.name}')
+ except:
+ print(f"[OK] Cluster created. -> {cluster}")
proxmox_cluster = cluster_all[0]
#
From 1febec89603ff6ee85281e8f7666422e4a875bc3 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Thu, 23 Mar 2023 15:26:37 +0000
Subject: [PATCH 084/313] comment 'RequestConfig' so that it pass the action
validation
---
netbox_proxbox/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/netbox_proxbox/views.py b/netbox_proxbox/views.py
index 4ed893c..8284e4c 100755
--- a/netbox_proxbox/views.py
+++ b/netbox_proxbox/views.py
@@ -164,7 +164,7 @@ def get(self, request):
table = ProxmoxVMTable(self.queryset)
# RequestConfig is used to configure pagination of 25 object per page
- RequestConfig(request, paginate={"per_page": 25}).configure(table)
+ #RequestConfig(request, paginate={"per_page": 25}).configure(table)
return render(
request, "netbox_proxbox/proxmox_vm_list.html",
From 47f3eca424e7749591dd9ed5ce18ca450703f543 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Thu, 23 Mar 2023 20:38:48 +0000
Subject: [PATCH 085/313] change all print() to logging.
---
netbox_proxbox/proxbox_api/create/dcim.py | 14 ++++--
.../proxbox_api/create/virtualization.py | 15 +++---
netbox_proxbox/proxbox_api/remove.py | 28 ++++++-----
netbox_proxbox/proxbox_api/update.py | 50 ++++++++++---------
netbox_proxbox/proxbox_api/updates/node.py | 4 +-
.../proxbox_api/updates/virtual_machine.py | 41 +++++++--------
6 files changed, 82 insertions(+), 70 deletions(-)
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index c3105f7..28cfc4a 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -10,6 +10,8 @@
virtualization,
)
+import logging
+
#
# dcim.manufacturers
#
@@ -66,7 +68,9 @@ def device_type():
tags = [extras.tag().id]
)
except:
- return f"Error creating the '{proxbox_device_type_model}' device type. Possible errors: the model '{proxbox_device_type_model}' or slug '{proxbox_device_type_slug}' is already used."
+ log_message = f"Error creating the '{proxbox_device_type_model}' device type. Possible errors: the model '{proxbox_device_type_model}' or slug '{proxbox_device_type_slug}' is already used."
+ logging.error(log_message)
+ return log_message
else:
device_type = proxbox_device_types
@@ -164,7 +168,7 @@ def node(proxmox_node):
)
return search_device
except Exception as error:
- print(error)
+ logging.error(error)
try:
# CREATE
@@ -172,10 +176,10 @@ def node(proxmox_node):
netbox_obj = nb.dcim.devices.create(node_json)
return netbox_obj
except Exception as error:
- print(error)
+ logging.error(error)
finally:
- print("[proxbox_api.create.node] Creation of NODE failed.")
+ logging.error("[proxbox_api.create.node] Creation of NODE failed.")
netbox_obj = None
# If NODE is not DUPLICATED, then CREATE it.
@@ -185,7 +189,7 @@ def node(proxmox_node):
netbox_obj = nb.dcim.devices.create(node_json)
except:
- print("[proxbox_api.create.node] Creation of NODE failed.")
+ logging.error("[proxbox_api.create.node] Creation of NODE failed.")
netbox_obj = None
return netbox_obj
diff --git a/netbox_proxbox/proxbox_api/create/virtualization.py b/netbox_proxbox/proxbox_api/create/virtualization.py
index 08b2e2e..56feaef 100755
--- a/netbox_proxbox/proxbox_api/create/virtualization.py
+++ b/netbox_proxbox/proxbox_api/create/virtualization.py
@@ -12,6 +12,8 @@
extras,
)
+import logging
+
#
# virtualization.cluster_types
#
@@ -69,7 +71,7 @@ def cluster():
type = cluster_type().slug
)
except ValueError as error:
- print(f"[ERROR] More than one cluster is created with the name '{proxmox_cluster_name}', making proxbox to abort update.\n > {error}")
+ logging.error(f"[ERROR] More than one cluster is created with the name '{proxmox_cluster_name}', making proxbox to abort update.\n > {error}")
return
nb_cluster_name = None
@@ -77,7 +79,7 @@ def cluster():
if cluster_proxbox != None:
nb_cluster_name = cluster_proxbox.name
except Exception as error:
- print(f"[ERROR] {error}")
+ logging.error(f"[ERROR] {error}")
duplicate = False
try:
@@ -85,7 +87,7 @@ def cluster():
if cluster_proxbox != None:
search_tag = cluster_proxbox.tags.index(extras.tag())
except ValueError as error:
- print(f"[WARNING] Cluster with the same name as {nb_cluster_name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
+ logging.warning(f"[WARNING] Cluster with the same name as {nb_cluster_name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
cluster_proxbox = False
duplicate = True
@@ -97,7 +99,6 @@ def cluster():
# Check if duplicated device was already created.
try:
- print(proxmox_cluster_name)
search_device = nb.virtualization.clusters.get(
name = proxmox_cluster_name
)
@@ -106,7 +107,7 @@ def cluster():
return search_device
except Exception as error:
- print(f"[ERROR] {error}")
+ logging.error(f"[ERROR] {error}")
else:
return cluster_proxbox
@@ -157,7 +158,7 @@ def virtual_machine(proxmox_vm, duplicate):
vm_json["status"] = 'offline'
if duplicate:
- print("VM/CT is duplicated")
+ logging.warning("[WARNING] VM/CT is duplicated")
vm_json["name"] = f"{proxmox_vm['name']} (2)"
else:
vm_json["name"] = proxmox_vm['name']
@@ -173,7 +174,7 @@ def virtual_machine(proxmox_vm, duplicate):
return netbox_obj
except:
- print("[proxbox.create.virtual_machine] Creation of VM/CT failed.")
+ logging.error("[proxbox.create.virtual_machine] Creation of VM/CT failed.")
netbox_obj = None
diff --git a/netbox_proxbox/proxbox_api/remove.py b/netbox_proxbox/proxbox_api/remove.py
index bf21ce1..9556d4b 100755
--- a/netbox_proxbox/proxbox_api/remove.py
+++ b/netbox_proxbox/proxbox_api/remove.py
@@ -6,6 +6,8 @@
NETBOX_SESSION as nb,
)
+import logging
+
# Verify if VM/CT exists on Proxmox
def is_vm_on_proxmox(netbox_vm):
# Get json of all virtual machines from Proxmox
@@ -19,7 +21,7 @@ def is_vm_on_proxmox(netbox_vm):
# Analyze local_context of VM
if local_context == None:
- print(f'[WARNING] "local_context_data" not filled. -> {netbox_name}')
+ logging.warning(f'[WARNING] "local_context_data" not filled. -> {netbox_name}')
else:
# "proxmox" key of "local_context_data"
@@ -27,7 +29,7 @@ def is_vm_on_proxmox(netbox_vm):
# If null value, returns error
if proxmox_json == None:
- print(f"[WARNING] 'local_context_data' does not have 'proxmox' json key -> {netbox_name}")
+ logging.warning(f"[WARNING] 'local_context_data' does not have 'proxmox' json key -> {netbox_name}")
else:
# Netbox VM/CT ID
@@ -35,7 +37,7 @@ def is_vm_on_proxmox(netbox_vm):
# If null value, returns error
if netbox_id == None:
- print(f"[WARNING] 'proxmox' doest not have 'id' key -> {netbox_name}")
+ logging.warning(f"[WARNING] 'proxmox' doest not have 'id' key -> {netbox_name}")
# List names of VM/CT's from Proxmox
@@ -73,14 +75,14 @@ def is_vm_on_proxmox(netbox_vm):
local_context = netbox_vm.local_context_data
if local_context != None:
- print(f"[OK] 'local_context' updated' -> {netbox_name}")
+ logging.info(f"[OK] 'local_context' updated' -> {netbox_name}")
proxmox_json = local_context.get("proxmox")
netbox_id = proxmox_json.get("id")
else:
- print(f"[ERROR] 'local_context' is empty -> {netbox_name}")
+ logging.error(f"[ERROR] 'local_context' is empty -> {netbox_name}")
else:
- print(f"[WARNING] 'local_context' was not updated (error or already updated) -> {netbox_name}")
+ logging.warning(f"[WARNING] 'local_context' was not updated (error or already updated) -> {netbox_name}")
# Search VM on Proxmox by using ID
@@ -97,7 +99,7 @@ def is_vm_on_proxmox(netbox_vm):
if id_on_px == True:
return True
else:
- print(f"[WARNING] NAME exists on Proxmox, but ID does not. -> {netbox_name}")
+ logging.warning(f"[WARNING] NAME exists on Proxmox, but ID does not. -> {netbox_name}")
return True
# Comparison failed, not able to find VM on Proxmox
@@ -122,7 +124,7 @@ def all():
if vm_on_proxmox == True:
log_message = f'[OK] VM exists on both systems (Netbox and Proxmox) -> {netbox_name}'
- print(log_message)
+ logging.info(log_message)
log.append(log_message)
json_vm["result"] = False
@@ -130,7 +132,7 @@ def all():
# If VM does not exist on Proxmox, delete VM on Netbox.
elif vm_on_proxmox == False:
log_message = f"[WARNING] VM exists on Netbox, but not on Proxmox. Delete it! -> {netbox_name}"
- print(log_message)
+ logging.info(log_message)
log.append(log_message)
# Only delete VM that has proxbox tag registered
@@ -148,25 +150,25 @@ def all():
else:
log_message = f"[ERROR] VM will not be removed because the 'Proxbox' tag was not found. -> {netbox_name}"
- print(log_message)
+ logging.info(log_message)
log.append(log_message)
elif len(netbox_obj.tags) == 0:
log_message = f"[ERROR] VM will not be removed because the 'Proxbox' tag was not found. There is no tag configured.-> {netbox_name}"
- print(log_message)
+ logging.info(log_message)
log.append(log_message)
if delete_vm == True:
log_message = "[OK] VM successfully removed from Netbox."
- print(log_message)
+ logging.info(log_message)
log.append(log_message)
json_vm["result"] = True
else:
log_message = '[ERROR] Unexpected error trying to verify if VM exist on Proxmox'
- print(log_message)
+ logging.error(log_message)
log.append(log_message)
json_vm["result"] = False
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index a8466d1..0b0b5b5 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -19,6 +19,8 @@
from .create import extras
+import logging
+
# Call all functions to update Virtual Machine
def vm_full_update(netbox_vm, proxmox_vm):
changes = {}
@@ -143,7 +145,7 @@ def virtual_machine(**kwargs):
if proxmox_id != None:
proxmox_id_type = type(proxmox_id)
if 'int' not in str(proxmox_id_type):
- print(f'[ERROR] "proxmox_id" MUST be integer. Type used: {proxmox_id_type}')
+ logging.error(f'[ERROR] "proxmox_id" MUST be integer. Type used: {proxmox_id_type}')
#return False
json_vm["result"] = False
@@ -154,7 +156,7 @@ def virtual_machine(**kwargs):
if id != None:
id_type = type(id)
if 'int' not in str(id_type):
- print(f'[ERROR] "id" MUST be integer. Type used: {id_type}')
+ logging.error(f'[ERROR] "id" MUST be integer. Type used: {id_type}')
#return False
json_vm["result"] = False
@@ -166,7 +168,7 @@ def virtual_machine(**kwargs):
if name != None:
name_type = type(name)
if 'str' not in str(name_type):
- print(f'[ERROR] "name" MUST be string. Type used: {name_type}')
+ logging.error(f'[ERROR] "name" MUST be string. Type used: {name_type}')
#return False
json_vm["result"] = False
@@ -205,7 +207,7 @@ def virtual_machine(**kwargs):
# Analyze search result and returns error, if null value.
if proxmox_json == None:
- print("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_id'")
+ logging.error("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_id'")
json_vm["result"] = False
proxmox_vm_name = proxmox_json['name']
@@ -217,7 +219,7 @@ def virtual_machine(**kwargs):
# Analyze search result and returns error, if null value.
if proxmox_json == None:
- print("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_name'")
+ logging.error("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_name'")
json_vm["result"] = False
proxmox_vm_name = proxmox_json['name']
@@ -230,7 +232,7 @@ def virtual_machine(**kwargs):
# Analyze search result and returns error, if null value.
if proxmox_json == None:
- print("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_id'")
+ logging.error("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_id'")
json_vm["result"] = False
proxmox_vm_name = proxmox_json['name']
@@ -243,7 +245,7 @@ def virtual_machine(**kwargs):
# Analyze search result and returns error, if null value.
if proxmox_json == None:
- print("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_name'")
+ logging.error("[ERROR] Error to get Proxmox Virtual Machine using 'proxmox_name'")
json_vm["result"] = False
proxmox_vm_name = proxmox_json['name']
@@ -261,7 +263,7 @@ def virtual_machine(**kwargs):
if netbox_vm != None:
search_tag = netbox_vm.tags.index(extras.tag())
except ValueError as error:
- print(f"[WARNING] Virtual Machine or Container with the same name as {netbox_vm.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
+ logging.warning(f"[WARNING] Virtual Machine or Container with the same name as {netbox_vm.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
netbox_vm = False
duplicate = True
@@ -284,16 +286,16 @@ def virtual_machine(**kwargs):
# Analyze if VM needed to be updated on Netbox
if True in full_update_list:
- print(f'[OK] VM updated. -> {proxmox_vm_name}')
+ logging.info(f'[OK] VM updated. -> {proxmox_vm_name}')
else:
- print(f'[OK] VM already updated. -> {proxmox_vm_name}')
+ logging.info(f'[OK] VM already updated. -> {proxmox_vm_name}')
# In case none of condition works, return True anyway, since VM already exist.
json_vm["result"] = True
# If VM does not exist, create it on Netbox
else:
- print(f'[OK] VM does not exist on Netbox -> {proxmox_vm_name}')
+ logging.info(f'[OK] VM does not exist on Netbox -> {proxmox_vm_name}')
# Analyze if VM was sucessfully created.
netbox_vm = create.virtualization.virtual_machine(proxmox_json, duplicate)
@@ -309,20 +311,20 @@ def virtual_machine(**kwargs):
# Analyze if update was successful
if True in full_update_list:
- print(f'[OK] VM created -> {netbox_vm.name}')
+ logging.info(f'[OK] VM created -> {netbox_vm.name}')
# VM fully updated
json_vm["result"] = True
else:
- print(f'[OK] VM created, but full update failed -> {proxmox_vm_name}')
+ logging.info(f'[OK] VM created, but full update failed -> {proxmox_vm_name}')
# VM created with basic information
json_vm["result"] = True
else:
- print(f'[ERROR] VM not created. -> {proxmox_vm_name}')
+ logging.error(f'[ERROR] VM not created. -> {proxmox_vm_name}')
# VM not created
json_vm["result"] = False
@@ -343,7 +345,7 @@ def create_node():
# Node created
if netbox_node != None:
- print(f"[OK] Node created! -> {proxmox_node_name}")
+ logging.info(f"[OK] Node created! -> {proxmox_node_name}")
# Update rest of configuration
full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
@@ -355,15 +357,15 @@ def create_node():
# Analyze if update was successful
if True in full_update_list:
- print(f'[OK] NODE updated. -> {proxmox_node_name}')
+ logging.info(f'[OK] NODE updated. -> {proxmox_node_name}')
else:
- print(f'[OK] NODE already updated. -> {proxmox_node_name}')
+ logging.info(f'[OK] NODE already updated. -> {proxmox_node_name}')
return json_node
# Error with node creation
else:
- print(f'[ERROR] Something went wrong when creating the node.-> {proxmox_node_name} (2)')
+ logging.error(f'[ERROR] Something went wrong when creating the node.-> {proxmox_node_name} (2)')
json_node = {}
json_node["result"] = False
@@ -384,7 +386,7 @@ def create_node():
# Error with node creation
else:
- print(f'[ERROR] Something went wrong when creating the node.-> {proxmox_node_name}')
+ logging.error(f'[ERROR] Something went wrong when creating the node.-> {proxmox_node_name}')
json_node["result"] = False
else:
@@ -403,9 +405,9 @@ def create_node():
# Analyze if update was successful
if True in full_update_list:
- print(f'[OK] NODE updated. -> {proxmox_node_name}')
+ logging.info(f'[OK] NODE updated. -> {proxmox_node_name}')
else:
- print(f'[OK] NODE already updated. -> {proxmox_node_name}')
+ logging.info(f'[OK] NODE already updated. -> {proxmox_node_name}')
# return True as the node was successfully created.
json_node["node_id"] = netbox_node.id
@@ -414,7 +416,7 @@ def create_node():
except Exception as error:
# Tag was not found within device, so there is already existing device.
- print(f"[WARNING] Device with the same name as {netbox_search.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
+ logging.warning(f"[WARNING] Device with the same name as {netbox_search.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
proxmox_json["duplicate"] = True
proxmox_json["netbox_original_device"] = netbox_search
@@ -439,9 +441,9 @@ def all(**kwargs):
print('\n\n\nCLUSTER...')
try:
- print(f'[OK] CLUSTER created. -> {cluster.name}')
+ logging.info(f'[OK] CLUSTER created. -> {cluster.name}')
except:
- print(f"[OK] Cluster created. -> {cluster}")
+ logging.info(f"[OK] Cluster created. -> {cluster}")
proxmox_cluster = cluster_all[0]
#
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index 7e4cc1c..b57aaff 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -14,6 +14,8 @@
create,
)
+import logging
+
# Update STATUS field on /dcim/device/{id}
def status(netbox_node, proxmox_node):
#
@@ -98,7 +100,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
cluster_updated = False
except Exception as error:
- print(f"[ERROR] {error}")
+ logging.error(f"[ERROR] {error}")
else:
cluster_updated = False
diff --git a/netbox_proxbox/proxbox_api/updates/virtual_machine.py b/netbox_proxbox/proxbox_api/updates/virtual_machine.py
index 64a0a3f..c1dc232 100755
--- a/netbox_proxbox/proxbox_api/updates/virtual_machine.py
+++ b/netbox_proxbox/proxbox_api/updates/virtual_machine.py
@@ -21,6 +21,7 @@
from proxmoxer.core import ResourceException
+import logging
# Update "status" field on Netbox Virtual Machine based on Proxmox information
def status(netbox_vm, proxmox_vm):
@@ -113,7 +114,7 @@ def custom_fields(netbox_vm, proxmox_vm):
# Check if there is 'custom_field' configured on Netbox
if len(netbox_vm.custom_fields) == 0:
- print("[ERROR] There's no 'Custom Fields' registered by the Netbox Plugin user")
+ logging.error("[ERROR] There's no 'Custom Fields' registered by the Netbox Plugin user")
# If any 'custom_field' configured, get it and update, if necessary.
elif len(netbox_vm.custom_fields) > 0:
@@ -129,21 +130,21 @@ def custom_fields(netbox_vm, proxmox_vm):
if netbox_vm.custom_fields.get("proxmox_id") != proxmox_vm['vmid']:
custom_fields_update["proxmox_id"] = proxmox_vm['vmid']
else:
- print("[ERROR] 'proxmox_id' custom field not registered yet or configured incorrectly]")
+ logging.error("[ERROR] 'proxmox_id' custom field not registered yet or configured incorrectly]")
# Custom Field 'proxmox_node'
if 'proxmox_node' in custom_fields_names:
if netbox_vm.custom_fields.get("proxmox_node") != proxmox_vm['node']:
custom_fields_update["proxmox_node"] = proxmox_vm['node']
else:
- print("[ERROR] 'proxmox_node' custom field not registered yet or configured incorrectly")
+ logging.error("[ERROR] 'proxmox_node' custom field not registered yet or configured incorrectly")
# Custom Field 'proxmox_type'
if 'proxmox_type' in custom_fields_names:
if netbox_vm.custom_fields.get("proxmox_type") != proxmox_vm['type']:
custom_fields_update["proxmox_type"] = proxmox_vm['type']
else:
- print("[ERROR] 'proxmox_type' custom field not registered yet or configured incorrectly")
+ logging.error("[ERROR] 'proxmox_type' custom field not registered yet or configured incorrectly")
@@ -162,7 +163,7 @@ def custom_fields(netbox_vm, proxmox_vm):
# Verify HTTP reply CODE
if custom_field_updated != 200:
- print("[ERROR] Some error occured trying to update 'custom_fields' through HTTP Request. HTTP Code: {}. -> {}".format(custom_field_updated, netbox_vm.name))
+ logging.error("[ERROR] Some error occured trying to update 'custom_fields' through HTTP Request. HTTP Code: {}. -> {}".format(custom_field_updated, netbox_vm.name))
return False
else:
@@ -292,9 +293,9 @@ def interfaces(netbox_vm, proxmox_vm):
elif proxmox_vm['type'] == 'lxc':
vm_config = proxmox.nodes(proxmox_vm['node']).lxc(proxmox_vm['vmid']).config.get()
else:
- print('[ERROR] Unknown or unmanaged proxmox_vm_type')
+ logging.error('[ERROR] Unknown or unmanaged proxmox_vm_type')
except Exception as error:
- print(f"[ERROR] Unknown or unmanaged proxmox_vm_type\n > {error}")
+ logging.error(f"[ERROR] Unknown or unmanaged proxmox_vm_type\n > {error}")
return
_pmx_if = []
@@ -332,7 +333,7 @@ def interfaces(netbox_vm, proxmox_vm):
if pmx_if_mac not in [_if['mac_address'] for _if in _ntb_if]:
try:
if nb.virtualization.interfaces.get(virtual_machine_id=netbox_vm.id, virtual_machine=netbox_vm.name, name=pmx_if['name']):
- print("Interface already exist.")
+ logging.warning("[WARNING] Interface already exist.")
else:
# Create interface if does not exist.
netbox_interface = nb.virtualization.interfaces.create(virtual_machine_id=netbox_vm.id, virtual_machine=netbox_vm.id, name=pmx_if['name'], mac_address=pmx_if_mac, mtu=pmx_if['mtu'])
@@ -346,10 +347,10 @@ def interfaces(netbox_vm, proxmox_vm):
netbox_interface = nb.virtualization.interfaces.update([{'id': netbox_interface.id, 'name': pmx_if['name'], 'mac_address': pmx_if_mac, 'mtu': pmx_if['mtu']}])
updated = True
elif len(netbox_interface) > 1:
- print('[ERROR] too many results')
+ logging.error('[ERROR] Too many results')
return False
else:
- print('[ERROR] something went wrong while getting interface config from proxmox')
+ logging.error('[ERROR] Something went wrong while getting interface config from proxmox')
return False
for ntb_if_mac in [_if['mac_address'] for _if in _ntb_if]:
@@ -361,10 +362,10 @@ def interfaces(netbox_vm, proxmox_vm):
netbox_interface.delete()
updated = True
elif len(netbox_interface) > 1:
- print('[ERROR] too many results')
+ logging.error('[ERROR] Too many results')
return False
else:
- print('[ERROR] something went wrong while getting interface config from netbox')
+ logging.error('[ERROR] Something went wrong while getting interface config from netbox')
return False
return updated
@@ -400,7 +401,7 @@ def interfaces_ips(netbox_vm, proxmox_vm):
_if[_mac].append(ip.address.lower())
_ntb_ips.append(_if)
except ResourceException as e:
- print('[ERROR]' + str(e))
+ logging.error('[ERROR]' + str(e))
return False
elif proxmox_vm['type'] == 'lxc':
vm_config = proxmox.nodes(proxmox_vm['node']).lxc(proxmox_vm['vmid']).config.get()
@@ -430,7 +431,7 @@ def interfaces_ips(netbox_vm, proxmox_vm):
for pmx_mac in [list(x)[0] for x in _pmx_ips]:
if pmx_mac not in [list(y)[0] for y in _ntb_ips]:
- print('[ERROR] interface with mac_address %(pmx_mac)s from %(vm_name)s qemu-guest-agent is not defined in netbox' % {'pmx_mac': pmx_mac, 'vm_name': proxmox_vm['name']})
+ logging.error('[ERROR] interface with mac_address %(pmx_mac)s from %(vm_name)s qemu-guest-agent is not defined in netbox' % {'pmx_mac': pmx_mac, 'vm_name': proxmox_vm['name']})
else:
ntb_ips = next((_ips[pmx_mac] for _ips in _ntb_ips if list(_ips)[0] == pmx_mac), None)
pmx_ips = next((_ips[pmx_mac] for _ips in _pmx_ips if list(_ips)[0] == pmx_mac), None)
@@ -445,10 +446,10 @@ def interfaces_ips(netbox_vm, proxmox_vm):
netbox_interface = netbox_interface[0]
elif len(netbox_interface) > 1:
netbox_interface = None
- print('[ERROR] too many results')
+ logging.error('[ERROR] Too many results')
else:
netbox_interface = None
- print('[ERROR] something went wrong while getting interface object from netbox')
+ logging.error('[ERROR] Something went wrong while getting interface object from netbox')
if netbox_interface is not None:
if len(netbox_ipaddr):
if len(netbox_ipaddr) == 1:
@@ -457,13 +458,13 @@ def interfaces_ips(netbox_vm, proxmox_vm):
netbox_ipaddr = nb.ipam.ip_addresses.update([{'id': netbox_ipaddr.id, 'assigned_object_id': netbox_interface.id, 'assigned_object_type': 'virtualization.vminterface'}])
updated = True
elif len(netbox_ipaddr) > 1:
- print('[ERROR] too many results')
+ logging.error('[ERROR] Too many results')
else:
netbox_ipaddr = nb.ipam.ip_addresses.create(address=pmx_ip)
netbox_ipaddr = nb.ipam.ip_addresses.update([{'id': netbox_ipaddr.id, 'assigned_object_id': netbox_interface.id, 'assigned_object_type': 'virtualization.vminterface'}])
updated = True
- except Exception as error: print(error)
+ except Exception as error: logging.error(error)
for ntb_ip in ntb_ips:
@@ -474,7 +475,7 @@ def interfaces_ips(netbox_vm, proxmox_vm):
netbox_ipaddr[0].delete()
updated = True
elif len(netbox_ipaddr) > 1:
- print('[ERROR] too many results')
+ logging.error('[ERROR] Too many results')
else:
- print('[ERROR] something went wrong while getting ip object from netbox')
+ logging.error('[ERROR] Something went wrong while getting ip object from netbox')
return updated
From cef11104688c671166dc40684282e811c50dc361 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Thu, 23 Mar 2023 20:43:31 +0000
Subject: [PATCH 086/313] Add logging section to README
---
README.md | 35 +++++++++++++++++++++++++++++++----
1 file changed, 31 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index c422af3..acf6eb1 100755
--- a/README.md
+++ b/README.md
@@ -79,9 +79,11 @@ The following table shows the Netbox and Proxmox versions compatible (tested) wi
[4. Usage](#4-usage)
-[5. Contributing](#5-contributing)
+[5. Enable Logs][#5-enable-logs]
-[6. Roadmap](#6-roadmap)
+[6. Contributing](#5-contributing)
+
+[7. Roadmap](#6-roadmap)
---
@@ -305,14 +307,39 @@ It will redirect you to a new page and you just have to wait until the plugin ru
---
-## 5. Contributing
+## 5. Enable Logs
+
+So that Proxbox plugin logs what is happening to the terminal, copy the following code and paste to `configuration.py` Netbox configuration file:
+
+```python
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'handlers': {
+ 'console': {
+ 'class': 'logging.StreamHandler',
+ },
+ },
+ 'root': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+}
+```
+
+You can customize this using the following link: [Django Docs - Logging](https://docs.djangoproject.com/en/4.1/topics/logging/).
+Although the above standard configuration should do the trick to things work.
+
+---
+
+## 6. Contributing
Developing tools for this project based on [ntc-netbox-plugin-onboarding](https://github.com/networktocode/ntc-netbox-plugin-onboarding) repo.
Issues and pull requests are welcomed.
---
-## 6. Roadmap
+## 7. Roadmap
- Start using custom models to optimize the use of the Plugin and stop using 'Custom Fields'
- Automatically remove Nodes on Netbox when removed on Promox (as it already happens with Virtual Machines and Containers)
- Add individual update of VM/CT's and Nodes (currently is only possible to update all at once)
From 08067048d330c8e203ee265165e458c35ced52a1 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Thu, 23 Mar 2023 20:44:23 +0000
Subject: [PATCH 087/313] fix wrong markdown link
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index acf6eb1..2d74b59 100755
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ The following table shows the Netbox and Proxmox versions compatible (tested) wi
[4. Usage](#4-usage)
-[5. Enable Logs][#5-enable-logs]
+[5. Enable Logs](#5-enable-logs)
[6. Contributing](#5-contributing)
From 0584f6f2b0ca43074340dba60b9dbde67e2e79be Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Thu, 23 Mar 2023 20:44:55 +0000
Subject: [PATCH 088/313] fix another markdown links typo's
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 2d74b59..59cc7c6 100755
--- a/README.md
+++ b/README.md
@@ -81,9 +81,9 @@ The following table shows the Netbox and Proxmox versions compatible (tested) wi
[5. Enable Logs](#5-enable-logs)
-[6. Contributing](#5-contributing)
+[6. Contributing](#6-contributing)
-[7. Roadmap](#6-roadmap)
+[7. Roadmap](#7-roadmap)
---
From 4f09e817ec1ef9abce71c2ce5ecad1e2cd4379c7 Mon Sep 17 00:00:00 2001
From: Robin Dittrich
Date: Fri, 24 Mar 2023 08:31:36 +0100
Subject: [PATCH 089/313] Fixed the mgmt_only and proxmox_keep_interface bool
logic
---
netbox_proxbox/proxbox_api/updates/node.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index b57aaff..c8f5f8c 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -229,7 +229,7 @@ def interfaces(netbox_node, proxmox_json):
if iface not in [x.get('name') for x in _pmx_iface]:
ntb_iface = list(nb.dcim.interfaces.filter(device_id=netbox_node.id, name=iface))
if len(ntb_iface) == 1:
- if not ntb_iface[0].mgmt_only or not ntb_iface[0].custom_fields.get('proxmox_keep_interface', False):
+ if not ntb_iface[0].mgmt_only and not ntb_iface[0].custom_fields.get('proxmox_keep_interface', False):
ntb_iface[0].delete()
return updated
From 42a2bc5affd8c9ba643bb3d2690053428f28b443 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Tue, 28 Mar 2023 12:08:47 +0000
Subject: [PATCH 090/313] Create FastAPI app and make all functions
assynchronous
---
netbox_proxbox/main.py | 14 +++++
netbox_proxbox/proxbox_api/create/dcim.py | 39 ++++++++----
netbox_proxbox/proxbox_api/create/extras.py | 4 +-
.../proxbox_api/create/virtualization.py | 38 +++++++----
netbox_proxbox/proxbox_api/remove.py | 6 +-
netbox_proxbox/proxbox_api/update.py | 63 ++++++++++---------
netbox_proxbox/proxbox_api/updates/extras.py | 8 ++-
netbox_proxbox/proxbox_api/updates/node.py | 10 +--
.../proxbox_api/updates/virtual_machine.py | 16 ++---
netbox_proxbox/views.py | 14 +++--
setup.py | 7 ++-
11 files changed, 136 insertions(+), 83 deletions(-)
create mode 100644 netbox_proxbox/main.py
diff --git a/netbox_proxbox/main.py b/netbox_proxbox/main.py
new file mode 100644
index 0000000..39aef4f
--- /dev/null
+++ b/netbox_proxbox/main.py
@@ -0,0 +1,14 @@
+from fastapi import FastAPI
+from netbox_proxbox import proxbox_api
+
+app = FastAPI()
+
+
+@app.get("/full_update")
+async def full_update():
+ json_result = await proxbox_api.update.all()
+ return json_result
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int):
+ return {"item_id": item_id}
\ No newline at end of file
diff --git a/netbox_proxbox/proxbox_api/create/dcim.py b/netbox_proxbox/proxbox_api/create/dcim.py
index 28cfc4a..d81c006 100755
--- a/netbox_proxbox/proxbox_api/create/dcim.py
+++ b/netbox_proxbox/proxbox_api/create/dcim.py
@@ -15,7 +15,7 @@
#
# dcim.manufacturers
#
-def manufacturer():
+async def manufacturer():
proxbox_manufacturer_name = 'Proxbox Basic Manufacturer'
proxbox_manufacturer_slug = 'proxbox-manufacturer'
proxbox_manufacturer_desc = 'Manufacturer Proxbox will use if none is configured by user in PLUGINS_CONFIG'
@@ -46,7 +46,7 @@ def manufacturer():
#
# dcim.device_types
#
-def device_type():
+async def device_type():
proxbox_device_type_model = 'Proxbox Model'
proxbox_device_type_slug = 'proxbox-model'
proxbox_device_type_comments = "Device Type Proxbox will use when creating the Cluster's Nodes. When the Node is created, you can change the device type to the actual server model."
@@ -61,11 +61,11 @@ def device_type():
try:
# If Proxbox manufacturer does not exist, create one.
device_type = nb.dcim.device_types.create(
- manufacturer = manufacturer().id,
+ manufacturer = await manufacturer().id,
model = proxbox_device_type_model,
slug = proxbox_device_type_slug,
comments = proxbox_device_type_comments,
- tags = [extras.tag().id]
+ tags = await [extras.tag().id]
)
except:
log_message = f"Error creating the '{proxbox_device_type_model}' device type. Possible errors: the model '{proxbox_device_type_model}' or slug '{proxbox_device_type_slug}' is already used."
@@ -81,7 +81,7 @@ def device_type():
#
# dcim.sites
#
-def site(**kwargs):
+async def site(**kwargs):
# If site_id equals to 0, consider it is not configured by user and must be created by Proxbox
site_id = kwargs.get('site_id', 0)
@@ -130,20 +130,33 @@ def site(**kwargs):
#
# dcim.devices (nodes)
#
-def node(proxmox_node):
+async def node(proxmox_node):
# Create json with basic NODE information
node_json = {}
node_json["name"] = proxmox_node['name']
- node_json["device_role"] = extras.role(role_id = NETBOX_NODE_ROLE_ID).id
- node_json["device_type"] = device_type().id
- node_json["site"] = site(site_id = NETBOX_SITE_ID).id
+
+ device_role = await extras.role(role_id = NETBOX_NODE_ROLE_ID)
+ node_json["device_role"] = device_role.id
+
+ device_type_id = await device_type()
+ node_json["device_type"] = device_type_id.id
+
+ site_id = await site(site_id = NETBOX_SITE_ID)
+ node_json["site"] = site_id.id
+
node_json["status"] = 'active'
- node_json["tags"] = [extras.tag().id]
- cluster = virtualization.cluster()
+ tags_id = await extras.tag()
+ tags_id = tags_id.id
+ node_json["tags"] = [tags_id]
+
+ cluster = await virtualization.cluster()
if cluster:
- if cluster != None:
- node_json["cluster"] = cluster.id
+ if isinstance(cluster, str):
+ print(cluster)
+ return
+
+ node_json["cluster"] = cluster.id
# If device already exists, append (2) to final of the name
check_duplicate = proxmox_node.get("duplicate", False)
diff --git a/netbox_proxbox/proxbox_api/create/extras.py b/netbox_proxbox/proxbox_api/create/extras.py
index 963c86f..7cdce61 100755
--- a/netbox_proxbox/proxbox_api/create/extras.py
+++ b/netbox_proxbox/proxbox_api/create/extras.py
@@ -6,7 +6,7 @@
#
# extras.tags
#
-def tag():
+async def tag():
proxbox_tag_name = 'Proxbox'
proxbox_tag_slug = 'proxbox'
@@ -40,7 +40,7 @@ def tag():
# dcim.device_roles
#
# OBS: this function is here and not in ./dcim.py since it is used by both NODE and VIRTUAL MACHINE.
-def role(**kwargs):
+async def role(**kwargs):
# If role_id equals to 0, consider it is not configured by user and must be created by Proxbox
role_id = kwargs.get("role_id", 0)
diff --git a/netbox_proxbox/proxbox_api/create/virtualization.py b/netbox_proxbox/proxbox_api/create/virtualization.py
index 56feaef..a312b55 100755
--- a/netbox_proxbox/proxbox_api/create/virtualization.py
+++ b/netbox_proxbox/proxbox_api/create/virtualization.py
@@ -17,7 +17,7 @@
#
# virtualization.cluster_types
#
-def cluster_type():
+async def cluster_type():
#
# Cluster Type
#
@@ -54,7 +54,7 @@ def cluster_type():
#
# virtualization.clusters
#
-def cluster():
+async def cluster():
#
# Cluster
#
@@ -66,9 +66,10 @@ def cluster():
# Name equal to Proxmox's Cluster name
# Cluster type equal to 'proxmox'
try:
+ cluster_type_slug = await cluster_type()
cluster_proxbox = nb.virtualization.clusters.get(
name = proxmox_cluster_name,
- type = cluster_type().slug
+ type = cluster_type_slug.slug
)
except ValueError as error:
logging.error(f"[ERROR] More than one cluster is created with the name '{proxmox_cluster_name}', making proxbox to abort update.\n > {error}")
@@ -85,7 +86,8 @@ def cluster():
try:
# Check if Proxbox tag exist.
if cluster_proxbox != None:
- search_tag = cluster_proxbox.tags.index(extras.tag())
+ tag = await extras.tag()
+ search_tag = cluster_proxbox.tags.index(tag)
except ValueError as error:
logging.warning(f"[WARNING] Cluster with the same name as {nb_cluster_name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
cluster_proxbox = False
@@ -113,10 +115,14 @@ def cluster():
try:
# Create the cluster with only name and cluster_type
+
+ cluster_type_id = await cluster_type()
+ tags_id = await extras.tag()
+
cluster = nb.virtualization.clusters.create(
name = proxmox_cluster_name,
- type = cluster_type().id,
- tags = [extras.tag().id]
+ type = cluster_type_id.id,
+ tags = [tags_id.id]
)
return cluster
except:
@@ -126,10 +132,13 @@ def cluster():
else:
try:
# Create the cluster with only name and cluster_type
+ cluster_type_id = await cluster_type()
+ tags_id = await extras.tag()
+
cluster = nb.virtualization.clusters.create(
name = proxmox_cluster_name,
- type = cluster_type().id,
- tags = [extras.tag().id]
+ type = cluster_type_id.id,
+ tags = [tags_id.id]
)
return cluster
except:
@@ -147,7 +156,7 @@ def cluster():
#
# virtualization.virtual_machines
#
-def virtual_machine(proxmox_vm, duplicate):
+async def virtual_machine(proxmox_vm, duplicate):
# Create json with basic VM/CT information
vm_json = {}
netbox_obj = None
@@ -163,10 +172,15 @@ def virtual_machine(proxmox_vm, duplicate):
else:
vm_json["name"] = proxmox_vm['name']
+ cluster_obj = await cluster()
vm_json["status"] = 'active'
- vm_json["cluster"] = cluster().id
- vm_json["role"] = extras.role(role_id = NETBOX_VM_ROLE_ID).id
- vm_json["tags"] = [extras.tag().id]
+ vm_json["cluster"] = cluster_obj.id
+
+ role_id = await extras.role(role_id = NETBOX_VM_ROLE_ID)
+ vm_json["role"] = role_id.id
+
+ tags_id = await extras.tag()
+ vm_json["tags"] = [tags_id.id]
# Create VM/CT with json 'vm_json'
try:
diff --git a/netbox_proxbox/proxbox_api/remove.py b/netbox_proxbox/proxbox_api/remove.py
index 9556d4b..b9c6d1e 100755
--- a/netbox_proxbox/proxbox_api/remove.py
+++ b/netbox_proxbox/proxbox_api/remove.py
@@ -9,7 +9,7 @@
import logging
# Verify if VM/CT exists on Proxmox
-def is_vm_on_proxmox(netbox_vm):
+async def is_vm_on_proxmox(netbox_vm):
# Get json of all virtual machines from Proxmox
all_proxmox_vms = proxmox.cluster.resources.get(type='vm')
@@ -69,7 +69,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 = await updates.local_context_data(netbox_vm, all_proxmox_vms[name_index])
if local_context_updated == True:
local_context = netbox_vm.local_context_data
@@ -105,7 +105,7 @@ def is_vm_on_proxmox(netbox_vm):
# Comparison failed, not able to find VM on Proxmox
return False
-def all():
+async def all():
json_vm_all = []
# Get all VM/CTs from Netbox
diff --git a/netbox_proxbox/proxbox_api/update.py b/netbox_proxbox/proxbox_api/update.py
index 0b0b5b5..a3cd4a3 100755
--- a/netbox_proxbox/proxbox_api/update.py
+++ b/netbox_proxbox/proxbox_api/update.py
@@ -22,25 +22,25 @@
import logging
# Call all functions to update Virtual Machine
-def vm_full_update(netbox_vm, proxmox_vm):
+async def vm_full_update(netbox_vm, proxmox_vm):
changes = {}
# Update 'status' field, if necessary.
- status_updated = updates.virtual_machine.status(netbox_vm, proxmox_vm)
+ status_updated = await updates.virtual_machine.status(netbox_vm, proxmox_vm)
# Update 'custom_fields' field, if necessary.
- custom_fields_updated = updates.virtual_machine.custom_fields(netbox_vm, proxmox_vm)
+ custom_fields_updated = await updates.virtual_machine.custom_fields(netbox_vm, proxmox_vm)
# Update 'local_context_data' json, if necessary.
- local_context_updated = updates.virtual_machine.local_context_data(netbox_vm, proxmox_vm)
+ local_context_updated = await updates.virtual_machine.local_context_data(netbox_vm, proxmox_vm)
# Update 'resources', like CPU, Memory and Disk, if necessary.
- resources_updated = updates.virtual_machine.resources(netbox_vm, proxmox_vm)
+ resources_updated = await updates.virtual_machine.resources(netbox_vm, proxmox_vm)
- interfaces_updated = updates.virtual_machine.interfaces(netbox_vm, proxmox_vm)
- ips_updated = updates.virtual_machine.interfaces_ips(netbox_vm, proxmox_vm)
+ interfaces_updated = await updates.virtual_machine.interfaces(netbox_vm, proxmox_vm)
+ ips_updated = await updates.virtual_machine.interfaces_ips(netbox_vm, proxmox_vm)
- tag_updated = updates.extras.tag(netbox_vm)
+ tag_updated = await updates.extras.tag(netbox_vm)
#changes = [custom_fields_updated, status_updated, local_context_updated, resources_updated]
changes = {
@@ -57,12 +57,12 @@ def vm_full_update(netbox_vm, proxmox_vm):
-def node_full_update(netbox_node, proxmox_json, proxmox_cluster):
+async def node_full_update(netbox_node, proxmox_json, proxmox_cluster):
changes = {}
- status_updated = updates.node.status(netbox_node, proxmox_json)
- cluster_updated = updates.node.cluster(netbox_node, proxmox_json, proxmox_cluster)
- interfaces_updated = updates.node.interfaces(netbox_node, proxmox_json)
+ status_updated = await updates.node.status(netbox_node, proxmox_json)
+ cluster_updated = await updates.node.cluster(netbox_node, proxmox_json, proxmox_cluster)
+ interfaces_updated = await updates.node.interfaces(netbox_node, proxmox_json)
changes = {
"status" : status_updated,
@@ -126,7 +126,7 @@ def search_by_id(id):
# Makes all necessary checks so that VM/CT exist on Netbox.
-def virtual_machine(**kwargs):
+async def virtual_machine(**kwargs):
# JSON containing the result of the VM changes
json_vm = {}
@@ -261,7 +261,9 @@ def virtual_machine(**kwargs):
try:
# Check if Proxbox tag exist.
if netbox_vm != None:
- search_tag = netbox_vm.tags.index(extras.tag())
+ tag = await extras.tag()
+ search_tag = netbox_vm.tags.index(tag)
+
except ValueError as error:
logging.warning(f"[WARNING] Virtual Machine or Container with the same name as {netbox_vm.name} already exists.\n> Proxbox will create another one with (2) in the name\n{error}")
netbox_vm = False
@@ -270,7 +272,7 @@ def virtual_machine(**kwargs):
# VM Found:
if netbox_vm:
# Update Netbox information
- full_update = vm_full_update(netbox_vm, proxmox_json)
+ full_update = await vm_full_update(netbox_vm, proxmox_json)
# I made this way since dict.update didn't work
json_vm["vm_id"] = netbox_vm.id
@@ -298,12 +300,12 @@ def virtual_machine(**kwargs):
logging.info(f'[OK] VM does not exist on Netbox -> {proxmox_vm_name}')
# Analyze if VM was sucessfully created.
- netbox_vm = create.virtualization.virtual_machine(proxmox_json, duplicate)
+ netbox_vm = await create.virtualization.virtual_machine(proxmox_json, duplicate)
# VM created with basic information
if netbox_vm != None:
# Update rest of configuration
- full_update = vm_full_update(netbox_vm, proxmox_json)
+ full_update = await vm_full_update(netbox_vm, proxmox_json)
json_vm = full_update
json_vm["vm_id"] = netbox_vm.id
@@ -333,22 +335,22 @@ def virtual_machine(**kwargs):
-def nodes(**kwargs):
+async def nodes(**kwargs):
proxmox_cluster = kwargs.get('proxmox_cluster')
proxmox_json = kwargs.get('proxmox_json')
proxmox_node_name = proxmox_json.get("name")
- def create_node():
+ async def create_node():
# If node does not exist, create it.
- netbox_node = create.dcim.node(proxmox_json)
+ netbox_node = await create.dcim.node(proxmox_json)
# Node created
if netbox_node != None:
logging.info(f"[OK] Node created! -> {proxmox_node_name}")
# Update rest of configuration
- full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
+ full_update = await node_full_update(netbox_node, proxmox_json, proxmox_cluster)
json_node = full_update
json_node["result"] = True
json_node["node_id"] = netbox_node.id
@@ -377,7 +379,7 @@ def create_node():
# Search node on Netbox with Proxmox node name gotten
if netbox_search == None:
# If node does not exist, create it.
- json_node = create_node()
+ json_node = await create_node()
# Node created
if json_node != None:
@@ -392,13 +394,14 @@ def create_node():
else:
try:
# Check if Proxbox tag exist.
- search_tag = netbox_search.tags.index(extras.tag())
+ tag = await extras.tag()
+ search_tag = netbox_search.tags.index(tag)
# If node already exist, try updating it.
netbox_node = netbox_search
# Update Netbox node information, if necessary.
- full_update = node_full_update(netbox_node, proxmox_json, proxmox_cluster)
+ full_update = await node_full_update(netbox_node, proxmox_json, proxmox_cluster)
json_node = full_update
full_update_list = list(full_update.values())
@@ -421,7 +424,7 @@ def create_node():
proxmox_json["duplicate"] = True
proxmox_json["netbox_original_device"] = netbox_search
- json_node = create_node()
+ json_node = await create_node()
# return True as the node was successfully created.
json_node["name"] = proxmox_node_name
@@ -430,14 +433,14 @@ def create_node():
# Makes everything needed so that VIRTUAL MACHINES / CONTAINERS, NODES and CLUSTER exists on Netbox
-def all(**kwargs):
+async def all(**kwargs):
print("[Proxbox - Netbox plugin | Update All]")
cluster_all = proxmox.cluster.status.get()
#
# CLUSTER
#
- cluster = create.virtualization.cluster()
+ cluster = await create.virtualization.cluster()
print('\n\n\nCLUSTER...')
try:
@@ -455,7 +458,7 @@ def all(**kwargs):
# Get all NODES from Proxmox
for px_node_each in proxmox_nodes:
- node_updated = nodes(proxmox_json = px_node_each, proxmox_cluster = proxmox_cluster)
+ node_updated = await nodes(proxmox_json = px_node_each, proxmox_cluster = proxmox_cluster)
nodes_list.append(node_updated)
@@ -469,7 +472,7 @@ def all(**kwargs):
print('\nUPDATE ALL...')
# Get all VM/CTs from Proxmox
for px_vm_each in proxmox.cluster.resources.get(type='vm'):
- vm_updated = virtual_machine(proxmox_json = px_vm_each)
+ vm_updated = await virtual_machine(proxmox_json = px_vm_each)
virtualmachines_list.append(vm_updated)
@@ -479,7 +482,7 @@ def all(**kwargs):
# Remove Netbox's old data
if remove_unused == True:
print('\nREMOVE UNUSED DATA...')
- remove_info = remove.all()
+ remove_info = await remove.all()
else:
remove_info = False
#
diff --git a/netbox_proxbox/proxbox_api/updates/extras.py b/netbox_proxbox/proxbox_api/updates/extras.py
index 8658b0d..e195092 100755
--- a/netbox_proxbox/proxbox_api/updates/extras.py
+++ b/netbox_proxbox/proxbox_api/updates/extras.py
@@ -2,7 +2,7 @@
create,
)
-def tag(netbox_vm):
+async def tag(netbox_vm):
# Get current tags
tags = netbox_vm.tags
@@ -12,9 +12,11 @@ def tag(netbox_vm):
tags_name.append(tag.name)
+ tags = await create.extras.tag()
+
# If Proxbox not found int Netbox tag's list, update object with the tag.
- if create.extras.tag().name not in tags_name:
- tags.append(create.extras.tag().id)
+ if tags.name not in tags_name:
+ tags.append(tags.id)
netbox_vm.tags = tags
diff --git a/netbox_proxbox/proxbox_api/updates/node.py b/netbox_proxbox/proxbox_api/updates/node.py
index b57aaff..17c1d94 100755
--- a/netbox_proxbox/proxbox_api/updates/node.py
+++ b/netbox_proxbox/proxbox_api/updates/node.py
@@ -17,7 +17,7 @@
import logging
# Update STATUS field on /dcim/device/{id}
-def status(netbox_node, proxmox_node):
+async def status(netbox_node, proxmox_node):
#
# Compare STATUS
#
@@ -57,7 +57,7 @@ def status(netbox_node, proxmox_node):
# Update CLUSTER field on /dcim/device/{id}
-def cluster(netbox_node, proxmox_node, proxmox_cluster):
+async def cluster(netbox_node, proxmox_node, proxmox_cluster):
#
# Compare CLUSTER
#
@@ -69,7 +69,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
# If cluster is not filled or even filled, but different from actual cluster, update it.
if netbox_node.cluster.name != proxmox_cluster['name'] or netbox_node.cluster.name == None:
# Search for Proxmox Cluster using create.cluster() function
- cluster_id = create.virtualization.cluster().id
+ cluster_id = await create.virtualization.cluster().id
# Use Cluster ID to update NODE information
netbox_node.cluster.id = cluster_id
@@ -85,7 +85,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
# If cluster is empty, update it.
elif proxmox_cluster == None:
# Search for Proxmox Cluster using create.cluster() function
- cluster_id = create.virtualization.cluster().id
+ cluster_id = await create.virtualization.cluster().id
# Use Cluster ID to update NODE information
netbox_node.cluster.id = cluster_id
@@ -106,7 +106,7 @@ def cluster(netbox_node, proxmox_node, proxmox_cluster):
return cluster_updated
-def interfaces(netbox_node, proxmox_json):
+async def interfaces(netbox_node, proxmox_json):
updated = False
_int_port = ['OVSIntPort']
_lag_port = ['OVSBond']
diff --git a/netbox_proxbox/proxbox_api/updates/virtual_machine.py b/netbox_proxbox/proxbox_api/updates/virtual_machine.py
index c1dc232..b41c00b 100755
--- a/netbox_proxbox/proxbox_api/updates/virtual_machine.py
+++ b/netbox_proxbox/proxbox_api/updates/virtual_machine.py
@@ -24,7 +24,7 @@
import logging
# Update "status" field on Netbox Virtual Machine based on Proxmox information
-def status(netbox_vm, proxmox_vm):
+async def status(netbox_vm, proxmox_vm):
# False = status not changed on Netbox
# True = status changed on Netbox
status_updated = False
@@ -64,14 +64,14 @@ def status(netbox_vm, proxmox_vm):
-def site(**kwargs):
+async def site(**kwargs):
# If site_id equals to 0, consider it is not configured by user and must be created by Proxbox
site_id = kwargs.get('site_id', 0)
# Function that modifies 'custom_field' of Netbox Virtual Machine.
# It uses HTTP Request and not Pynetbox (as I was not able to).
-def http_update_custom_fields(**kwargs):
+async def http_update_custom_fields(**kwargs):
# Saves kwargs variables
domain_with_http = kwargs.get('domain_with_http')
token = kwargs.get('token')
@@ -108,7 +108,7 @@ def http_update_custom_fields(**kwargs):
# Update 'custom_fields' field on Netbox Virtual Machine based on Proxbox
-def custom_fields(netbox_vm, proxmox_vm):
+async def custom_fields(netbox_vm, proxmox_vm):
# Create the new 'custom_field' with info from Proxmox
custom_fields_update = {}
@@ -177,7 +177,7 @@ def custom_fields(netbox_vm, proxmox_vm):
# Update 'local_context_data' field on Netbox Virtual Machine based on Proxbox
-def local_context_data(netbox_vm, proxmox_vm):
+async def local_context_data(netbox_vm, proxmox_vm):
current_local_context = netbox_vm.local_context_data
proxmox_values = {}
@@ -226,7 +226,7 @@ def local_context_data(netbox_vm, proxmox_vm):
# Updates following fields based on Proxmox: "vcpus", "memory", "disk", if necessary.
-def resources(netbox_vm, proxmox_vm):
+async def resources(netbox_vm, proxmox_vm):
# Save values from Proxmox
vcpus = float(proxmox_vm["maxcpu"])
@@ -285,7 +285,7 @@ def resources(netbox_vm, proxmox_vm):
else:
return False
-def interfaces(netbox_vm, proxmox_vm):
+async def interfaces(netbox_vm, proxmox_vm):
updated = False
try:
if proxmox_vm['type'] == 'qemu':
@@ -369,7 +369,7 @@ def interfaces(netbox_vm, proxmox_vm):
return False
return updated
-def interfaces_ips(netbox_vm, proxmox_vm):
+async def interfaces_ips(netbox_vm, proxmox_vm):
updated = False
if proxmox_vm['status'] == 'running':
_pmx_ips = []
diff --git a/netbox_proxbox/views.py b/netbox_proxbox/views.py
index 8284e4c..c01ed40 100755
--- a/netbox_proxbox/views.py
+++ b/netbox_proxbox/views.py
@@ -1,5 +1,6 @@
from django.shortcuts import get_object_or_404, render
from django.urls import reverse_lazy
+
# 'View' is a django subclass. Basic type of class-based views
from django.views import View
from django.views.generic.edit import CreateView, DeleteView, UpdateView
@@ -24,6 +25,11 @@
from . import ProxboxConfig
+import requests
+
+async def get_json_result():
+ return await proxbox_api.update.all(remove_unused = True)
+
class HomeView(View):
"""Homepage"""
template_name = 'netbox_proxbox/home.html'
@@ -88,16 +94,16 @@ class ProxmoxFullUpdate(PermissionRequiredMixin, View):
# Define permission
permission_required = "netbox_proxbox.view_proxmoxvm"
-
-
-
# service incoming GET HTTP requests
# 'pk' value is passed to get() via URL defined in urls.py
def get(self, request):
"""Get request."""
- json_result = proxbox_api.update.all(remove_unused = True)
+ json_result = None
+ try:
+ json_result = requests.get('http://localhost:8004/full_update').json()
+ except Exception as error: print(error)
return render(
request,
diff --git a/setup.py b/setup.py
index 3bc93e7..ca4fea0 100755
--- a/setup.py
+++ b/setup.py
@@ -21,8 +21,9 @@
'requests>=2',
'pynetbox>=5',
'paramiko>=2',
- 'proxmoxer>=1'
-
+ 'proxmoxer>=1',
+ 'fastapi[all]',
+ 'uvicorn[standard]',
]
dev_requires = [
@@ -61,5 +62,5 @@
extras_require={
"dev": dev_requires,
},
- python_requires= '>=3.6',
+ python_requires= '>=3.9',
)
From d7e6ba589e078cfa73a7d00205132515038e242b Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Tue, 28 Mar 2023 14:14:45 +0000
Subject: [PATCH 091/313] Add FastAPI example to README and to HomeView
---
README.md | 51 ++--
netbox_proxbox/__init__.py | 6 +-
netbox_proxbox/main.py | 2 +
netbox_proxbox/proxbox_api/plugins_config.py | 15 +-
.../static/netbox_proxbox/fastapi_logo.png | Bin 0 -> 14936 bytes
netbox_proxbox/static/proxmox-logo.svg | 243 ------------------
.../templates/netbox_proxbox/home.html | 37 +++
netbox_proxbox/views.py | 27 +-
8 files changed, 109 insertions(+), 272 deletions(-)
create mode 100644 netbox_proxbox/static/netbox_proxbox/fastapi_logo.png
delete mode 100644 netbox_proxbox/static/proxmox-logo.svg
diff --git a/README.md b/README.md
index 59cc7c6..7673b62 100755
--- a/README.md
+++ b/README.md
@@ -148,30 +148,35 @@ 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
- },
- 'netbox': {
- 'domain': 'localhost', # Ensure localhost is added to ALLOWED_HOSTS
- 'http_port': 8001, # Gunicorn port.
- 'token': '0dd7cddfaee3b38bbffbd2937d44c4a03f9c9d38',
- 'ssl': False, # There is no support to SSL on Netbox yet, so let it always False.
- 'settings': {
- 'virtualmachine_role_id' : 0,
- 'node_role_id' : 0,
- 'site_id': 0
- }
- }
+ '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
+ },
+ 'netbox': {
+ 'domain': 'localhost', # Ensure localhost is added to ALLOWED_HOSTS
+ 'http_port': 8001, # Gunicorn port.
+ 'token': '0dd7cddfaee3b38bbffbd2937d44c4a03f9c9d38',
+ 'ssl': False, # There is no support to SSL on Netbox yet, so let it always False.
+ 'settings': {
+ 'virtualmachine_role_id' : 0,
+ 'node_role_id' : 0,
+ 'site_id': 0
+ }
+ },
+ 'fastapi': {
+ 'uvicorn_host' : '0.0.0.0',
+ 'uvicorn_port' : '8002',
}
+ }
+}
```
diff --git a/netbox_proxbox/__init__.py b/netbox_proxbox/__init__.py
index 054f72f..537ec71 100755
--- a/netbox_proxbox/__init__.py
+++ b/netbox_proxbox/__init__.py
@@ -32,7 +32,11 @@ class ProxboxConfig(PluginConfig):
'node_role_id' : 0,
'site_id': 0
}
- }
+ },
+ 'fastapi': {
+ 'uvicorn_host' : '0.0.0.0',
+ 'uvicorn_port' : '8002',
+ },
}
config = ProxboxConfig
diff --git a/netbox_proxbox/main.py b/netbox_proxbox/main.py
index 39aef4f..ac58890 100644
--- a/netbox_proxbox/main.py
+++ b/netbox_proxbox/main.py
@@ -1,9 +1,11 @@
+import uvicorn
from fastapi import FastAPI
from netbox_proxbox import proxbox_api
app = FastAPI()
+
@app.get("/full_update")
async def full_update():
json_result = await proxbox_api.update.all()
diff --git a/netbox_proxbox/proxbox_api/plugins_config.py b/netbox_proxbox/proxbox_api/plugins_config.py
index fa8150a..c476583 100755
--- a/netbox_proxbox/proxbox_api/plugins_config.py
+++ b/netbox_proxbox/proxbox_api/plugins_config.py
@@ -20,6 +20,7 @@
DEFAULT_PLUGINS_CONFIG = ProxboxConfig.default_settings
DEFAULT_PROXMOX_SETTING = DEFAULT_PLUGINS_CONFIG.get("proxmox")
DEFAULT_NETBOX_SETTING = DEFAULT_PLUGINS_CONFIG.get("netbox")
+DEFAULT_FASTAPI_SETTING = DEFAULT_PLUGINS_CONFIG.get("fastapi")
#
# Proxmox related settings
@@ -65,7 +66,7 @@
USER_PLUGINS_CONFIG = PLUGINS_CONFIG.get("netbox_proxbox")
PROXMOX_SETTING = USER_PLUGINS_CONFIG.get("proxmox", DEFAULT_PROXMOX_SETTING)
NETBOX_SETTING = USER_PLUGINS_CONFIG.get("netbox", DEFAULT_NETBOX_SETTING)
-
+FASTAPI_SETTING = USER_PLUGINS_CONFIG.get("fastapi", DEFAULT_FASTAPI_SETTING)
#
# Proxmox related settings
#
@@ -103,10 +104,20 @@
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)
+#
+# FastAPI (uvicorn) related settings
+#
+if FASTAPI_SETTING != None:
+ DEFAULT_FASTAPI_HOST = DEFAULT_FASTAPI_SETTING.get("uvicorn_host")
+ DEFAULT_FASTAPI_PORT = DEFAULT_FASTAPI_SETTING.get("uvicorn_port")
+
+ FASTAPI_HOST = FASTAPI_SETTING.get("uvicorn_host", DEFAULT_FASTAPI_HOST)
+ FASTAPI_PORT = FASTAPI_SETTING.get("uvicorn_port", DEFAULT_FASTAPI_PORT)
+
####################################################################################################
# #
-# WITH PLUGIN CONFIGURED, STARTS BOTH PROXMOX AND NETBOX SESSION #
+# WITH PLUGIN CONFIGURED, STARTS PROXMOX, NETBOX AND UVICORN SESSIONS #
# #
####################################################################################################
diff --git a/netbox_proxbox/static/netbox_proxbox/fastapi_logo.png b/netbox_proxbox/static/netbox_proxbox/fastapi_logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..f6c6d93c4d652abc064ccf717d3245c2462ac0ab
GIT binary patch
literal 14936
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
literal 0
HcmV?d00001
diff --git a/netbox_proxbox/static/proxmox-logo.svg b/netbox_proxbox/static/proxmox-logo.svg
deleted file mode 100644
index bc5d22a..0000000
--- a/netbox_proxbox/static/proxmox-logo.svg
+++ /dev/null
@@ -1,243 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- image/svg+xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/netbox_proxbox/templates/netbox_proxbox/home.html b/netbox_proxbox/templates/netbox_proxbox/home.html
index 8e95eb1..3239eec 100644
--- a/netbox_proxbox/templates/netbox_proxbox/home.html
+++ b/netbox_proxbox/templates/netbox_proxbox/home.html
@@ -151,6 +151,43 @@
+
+
+
+
+
+
+
+
+
+ Uvicorn Host
+ {% if configuration.netbox_proxbox.fastapi.uvicorn_host %}
+ {{ configuration.netbox_proxbox.fastapi.uvicorn_host }}
+ {% else %}
+ {{ default_config.fastapi.uvicorn_host }} (default)
+ {% endif %}
+
+
+ Uvicorn Port
+ {% if configuration.netbox_proxbox.fastapi.uvicorn_port %}
+ {{ configuration.netbox_proxbox.fastapi.uvicorn_port }}
+ {% else %}
+ {{ default_config.fastapi.uvicorn_port }} (default)
+ {% endif %}
+
+
+
+
+
+
diff --git a/netbox_proxbox/views.py b/netbox_proxbox/views.py
index c01ed40..031a65b 100755
--- a/netbox_proxbox/views.py
+++ b/netbox_proxbox/views.py
@@ -24,11 +24,32 @@
from netbox import configuration
from . import ProxboxConfig
-
import requests
-async def get_json_result():
- return await proxbox_api.update.all(remove_unused = True)
+import logging
+
+
+# Deploy FastAPI with uvicorn instance
+try:
+ import subprocess
+
+ # Import config
+ fastapi_host = proxbox_api.plugins_config.FASTAPI_HOST
+ fastapi_port = proxbox_api.plugins_config.FASTAPI_PORT
+
+ # Check if there's already a process running with the same port
+ output = str(subprocess.run(["sudo", "netstat", "-tuln", "|", "grep", fastapi_port], capture_output=True).stdout)
+ if f"{fastapi_port}" in output:
+ raise Exception(f"Port '{fastapi_port}' is already being used.\nUnable to spawn uvicorn process, you'll have to change the port or kill the proccess running.\nTo do this, change 'PLUGINS_CONFIG' variable in 'configuration.py' Netbox")
+
+ # Spawn uvicorn process
+ uvicorn_spawn = ["uvicorn", "netbox-proxbox.netbox_proxbox.main:app", "--host", str(fastapi_host), "--port", str(fastapi_port)]
+ subprocess.Popen(uvicorn_spawn)
+except Exception as error:
+ log_message = f"[ERROR] {error}"
+ logging.error(log_message)
+ raise Exception(log_message)
+
class HomeView(View):
"""Homepage"""
From f3bc0743f12287e1830cca23432bdb19951ac819 Mon Sep 17 00:00:00 2001
From: emersonfelipesp
Date: Tue, 28 Mar 2023 14:43:47 +0000
Subject: [PATCH 092/313] Add development verification to know if use
'--reload' uvicorn parameter or not.
---
netbox_proxbox/main.py | 4 +++-
.../templates/netbox_proxbox/home.html | 4 +++-
netbox_proxbox/views.py | 17 ++++++++++++++---
3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/netbox_proxbox/main.py b/netbox_proxbox/main.py
index ac58890..bd6de58 100644
--- a/netbox_proxbox/main.py
+++ b/netbox_proxbox/main.py
@@ -4,7 +4,9 @@
app = FastAPI()
-
+@app.get("/")
+async def root():
+ return {"message": "Hello World! dsdsasdad"}
@app.get("/full_update")
async def full_update():
diff --git a/netbox_proxbox/templates/netbox_proxbox/home.html b/netbox_proxbox/templates/netbox_proxbox/home.html
index 3239eec..398b5d8 100644
--- a/netbox_proxbox/templates/netbox_proxbox/home.html
+++ b/netbox_proxbox/templates/netbox_proxbox/home.html
@@ -155,7 +155,9 @@