netbox-vcenter-server 0.3.1__py3-none-any.whl → 0.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- netbox_vcenter/__init__.py +1 -1
- netbox_vcenter/templates/netbox_vcenter/dashboard.html +47 -6
- netbox_vcenter/urls.py +1 -0
- netbox_vcenter/views.py +49 -0
- {netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/METADATA +1 -1
- {netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/RECORD +9 -9
- {netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/WHEEL +0 -0
- {netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/top_level.txt +0 -0
netbox_vcenter/__init__.py
CHANGED
|
@@ -52,7 +52,13 @@
|
|
|
52
52
|
</div>
|
|
53
53
|
{% endif %}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
<!-- Error/status messages from htmx -->
|
|
56
|
+
<div id="sync-status"></div>
|
|
57
|
+
|
|
58
|
+
<form hx-post="{% url 'plugins:netbox_vcenter:sync' %}"
|
|
59
|
+
hx-target="#sync-status"
|
|
60
|
+
hx-indicator="#sync-btn"
|
|
61
|
+
class="vcenter-sync-form">
|
|
56
62
|
{% csrf_token %}
|
|
57
63
|
|
|
58
64
|
<div class="mb-3">
|
|
@@ -78,8 +84,14 @@
|
|
|
78
84
|
<br><small class="text-muted">{{ form.verify_ssl.help_text }}</small>
|
|
79
85
|
</div>
|
|
80
86
|
|
|
81
|
-
<button type="submit" class="btn btn-primary">
|
|
82
|
-
<
|
|
87
|
+
<button type="submit" class="btn btn-primary" id="sync-btn">
|
|
88
|
+
<span id="sync-loading" class="htmx-indicator">
|
|
89
|
+
<span class="spinner-border spinner-border-sm me-1" role="status"></span>
|
|
90
|
+
Connecting...
|
|
91
|
+
</span>
|
|
92
|
+
<span class="sync-ready">
|
|
93
|
+
<i class="mdi mdi-sync"></i> Connect & Sync
|
|
94
|
+
</span>
|
|
83
95
|
</button>
|
|
84
96
|
</form>
|
|
85
97
|
</div>
|
|
@@ -144,6 +156,21 @@
|
|
|
144
156
|
</div>
|
|
145
157
|
</div>
|
|
146
158
|
|
|
159
|
+
<!-- Sync Loading Indicator (shown during htmx request) -->
|
|
160
|
+
<div id="sync-loading-panel" class="card mb-4">
|
|
161
|
+
<div class="card-body">
|
|
162
|
+
<div class="d-flex justify-content-center align-items-center py-5">
|
|
163
|
+
<div class="text-center">
|
|
164
|
+
<div class="spinner-border text-primary mb-3" role="status" style="width: 3rem; height: 3rem;">
|
|
165
|
+
<span class="visually-hidden">Loading...</span>
|
|
166
|
+
</div>
|
|
167
|
+
<p class="text-muted mb-0">Connecting to vCenter and fetching VMs...</p>
|
|
168
|
+
<p class="text-muted small">This may take a moment if MFA is required.</p>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
147
174
|
<!-- VM List -->
|
|
148
175
|
{% if vms %}
|
|
149
176
|
<div class="card">
|
|
@@ -247,12 +274,26 @@
|
|
|
247
274
|
</div>
|
|
248
275
|
{% elif selected_server and selected_server != 'all' and not cached_data|get_key:selected_server %}
|
|
249
276
|
<div class="alert alert-info">
|
|
250
|
-
<i class="mdi mdi-information"></i>
|
|
251
|
-
No cached data for <strong>{{ selected_server }}</strong>.
|
|
252
|
-
Enter your credentials and click "Connect & Sync" to fetch VMs.
|
|
277
|
+
<i class="mdi mdi-information"></i> No cached data for <strong>{{ selected_server }}</strong>. Enter your credentials and click "Connect & Sync" to fetch VMs.
|
|
253
278
|
</div>
|
|
254
279
|
{% endif %}
|
|
255
280
|
|
|
281
|
+
<style>
|
|
282
|
+
/* htmx indicator on the sync button */
|
|
283
|
+
#sync-btn .htmx-indicator { display: none; }
|
|
284
|
+
#sync-btn.htmx-request .htmx-indicator { display: inline; }
|
|
285
|
+
#sync-btn.htmx-request .sync-ready { display: none; }
|
|
286
|
+
#sync-btn.htmx-request { pointer-events: none; opacity: 0.7; }
|
|
287
|
+
/* Disable form inputs while syncing */
|
|
288
|
+
.vcenter-sync-form:has(#sync-btn.htmx-request) input,
|
|
289
|
+
.vcenter-sync-form:has(#sync-btn.htmx-request) select { pointer-events: none; opacity: 0.7; }
|
|
290
|
+
/* Loading panel - hidden by default, shown during sync */
|
|
291
|
+
#sync-loading-panel { display: none; }
|
|
292
|
+
body:has(#sync-btn.htmx-request) #sync-loading-panel { display: block; }
|
|
293
|
+
/* Hide "no cached data" alerts during sync */
|
|
294
|
+
body:has(#sync-btn.htmx-request) .alert-info { display: none; }
|
|
295
|
+
</style>
|
|
296
|
+
|
|
256
297
|
<script>
|
|
257
298
|
document.addEventListener('DOMContentLoaded', function() {
|
|
258
299
|
const selectAll = document.getElementById('select-all');
|
netbox_vcenter/urls.py
CHANGED
|
@@ -6,6 +6,7 @@ from . import views
|
|
|
6
6
|
|
|
7
7
|
urlpatterns = [
|
|
8
8
|
path("", views.VCenterDashboardView.as_view(), name="dashboard"),
|
|
9
|
+
path("sync/", views.VCenterSyncView.as_view(), name="sync"),
|
|
9
10
|
path("refresh/<str:server>/", views.VCenterRefreshView.as_view(), name="refresh"),
|
|
10
11
|
path("import/", views.VMImportView.as_view(), name="import"),
|
|
11
12
|
path("compare/", views.VMComparisonView.as_view(), name="compare"),
|
netbox_vcenter/views.py
CHANGED
|
@@ -310,6 +310,55 @@ class VCenterRefreshView(View):
|
|
|
310
310
|
return redirect(f"/plugins/vcenter/?server={server}")
|
|
311
311
|
|
|
312
312
|
|
|
313
|
+
class VCenterSyncView(View):
|
|
314
|
+
"""Async sync endpoint for htmx - connects to vCenter and caches VMs."""
|
|
315
|
+
|
|
316
|
+
def post(self, request):
|
|
317
|
+
"""Connect to vCenter and fetch VMs, return htmx response."""
|
|
318
|
+
from django.http import HttpResponse
|
|
319
|
+
|
|
320
|
+
form = VCenterConnectForm(request.POST)
|
|
321
|
+
|
|
322
|
+
if not form.is_valid():
|
|
323
|
+
return HttpResponse(
|
|
324
|
+
'<div class="alert alert-danger"><i class="mdi mdi-alert-circle"></i> '
|
|
325
|
+
"Invalid form data. Please check your inputs.</div>",
|
|
326
|
+
status=400,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
server = form.cleaned_data["server"]
|
|
330
|
+
username = form.cleaned_data["username"]
|
|
331
|
+
password = form.cleaned_data["password"]
|
|
332
|
+
verify_ssl = form.cleaned_data.get("verify_ssl", False)
|
|
333
|
+
|
|
334
|
+
# Connect and fetch VMs (this is the slow part with Duo MFA)
|
|
335
|
+
vms, error = connect_and_fetch(server, username, password, verify_ssl)
|
|
336
|
+
|
|
337
|
+
if error:
|
|
338
|
+
return HttpResponse(
|
|
339
|
+
f'<div class="alert alert-danger"><i class="mdi mdi-alert-circle"></i> '
|
|
340
|
+
f"<strong>Connection Failed:</strong> {error}</div>",
|
|
341
|
+
status=400,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# Cache the data (no timeout - persists until manual refresh)
|
|
345
|
+
cache_data = {
|
|
346
|
+
"vms": vms,
|
|
347
|
+
"timestamp": timezone.now().isoformat(),
|
|
348
|
+
"server": server,
|
|
349
|
+
"count": len(vms),
|
|
350
|
+
}
|
|
351
|
+
cache.set(get_cache_key(server), cache_data, None)
|
|
352
|
+
|
|
353
|
+
# Add success message for the redirected page
|
|
354
|
+
messages.success(request, f"Successfully synced {len(vms)} VMs from {server}")
|
|
355
|
+
|
|
356
|
+
# Return HX-Redirect header to trigger page reload with new data
|
|
357
|
+
response = HttpResponse(status=200)
|
|
358
|
+
response["HX-Redirect"] = f"/plugins/vcenter/?server={server}"
|
|
359
|
+
return response
|
|
360
|
+
|
|
361
|
+
|
|
313
362
|
class VMImportView(View):
|
|
314
363
|
"""Import selected VMs from vCenter to NetBox."""
|
|
315
364
|
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
netbox_vcenter/__init__.py,sha256=
|
|
1
|
+
netbox_vcenter/__init__.py,sha256=dzyA5vBqt3PcYPtGRGOB4kxGDIr6tqWcjEzaeaaWlNo,3386
|
|
2
2
|
netbox_vcenter/client.py,sha256=_zRJQpZ-zlDwvVk87At-SHF7jTHBfP6Q3Z8CTvGV7GA,8422
|
|
3
3
|
netbox_vcenter/forms.py,sha256=WYjv1U37SimAoRTYLbHGfqVR0-QF1km02fUwLeu84GI,3131
|
|
4
4
|
netbox_vcenter/navigation.py,sha256=iQ5on_klzEI5rUsT4xXNTvP9vmtitiKVPiUd0r4HyuA,757
|
|
5
|
-
netbox_vcenter/urls.py,sha256=
|
|
6
|
-
netbox_vcenter/views.py,sha256=
|
|
5
|
+
netbox_vcenter/urls.py,sha256=GUxbJMqRtFIPZ_592jfovT1CGY62xPA7IW8MjSHmmJA,574
|
|
6
|
+
netbox_vcenter/views.py,sha256=xXUkQqAWA40oF4CU7NKk4XtQzxd1quoG1-Q_C2wQrwI,31469
|
|
7
7
|
netbox_vcenter/api/__init__.py,sha256=f5d-0NprTQjL9t0TC9RuDlwCvkA7974Dbm_cuPI5FBY,44
|
|
8
8
|
netbox_vcenter/api/urls.py,sha256=84-OcoT5K1jzckWIsFpAfstfFn8BCuMgMwE1tH8XtMY,103
|
|
9
9
|
netbox_vcenter/templates/netbox_vcenter/compare.html,sha256=5b6bGQnxKlgB5OvTeHuBf53_c4mLIahTV_OB99Soai4,10412
|
|
10
|
-
netbox_vcenter/templates/netbox_vcenter/dashboard.html,sha256=
|
|
10
|
+
netbox_vcenter/templates/netbox_vcenter/dashboard.html,sha256=ehmKh1HQkpDlDYMMMh8F-FRlTK01pFSQfp9CstGz968,14954
|
|
11
11
|
netbox_vcenter/templates/netbox_vcenter/import.html,sha256=Gv_e0VOEQnUxW6wxuLNIdzAYB-JW5CLeL7Afxz7b3lo,8052
|
|
12
12
|
netbox_vcenter/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
netbox_vcenter/templatetags/vcenter_tags.py,sha256=Ca6X3yyH43M-YqbEkZqapnqM_4hOqf0g-N1PikfY9xY,327
|
|
14
|
-
netbox_vcenter_server-0.
|
|
15
|
-
netbox_vcenter_server-0.
|
|
16
|
-
netbox_vcenter_server-0.
|
|
17
|
-
netbox_vcenter_server-0.
|
|
18
|
-
netbox_vcenter_server-0.
|
|
14
|
+
netbox_vcenter_server-0.4.1.dist-info/licenses/LICENSE,sha256=8-I2jh8bMe_hkWX6XfGtHF1aA6y1oqRusoMnkdmFzNA,10761
|
|
15
|
+
netbox_vcenter_server-0.4.1.dist-info/METADATA,sha256=f82jzMZBIeNRJwa_5iTPYugrWMedUIxtmxOQWI2UW3I,6374
|
|
16
|
+
netbox_vcenter_server-0.4.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
17
|
+
netbox_vcenter_server-0.4.1.dist-info/top_level.txt,sha256=jvm95otBzT6WKAfIM_UXVqOeHYYL59zgpyEcLEk3G8g,15
|
|
18
|
+
netbox_vcenter_server-0.4.1.dist-info/RECORD,,
|
|
File without changes
|
{netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{netbox_vcenter_server-0.3.1.dist-info → netbox_vcenter_server-0.4.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|