ipfabric_netbox 4.3.0b7__py3-none-any.whl → 4.3.0b9__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.
- ipfabric_netbox/__init__.py +1 -1
- ipfabric_netbox/jobs.py +35 -13
- ipfabric_netbox/migrations/0020_clean_scheduled_jobs.py +70 -0
- ipfabric_netbox/models.py +50 -22
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricingestion.html +4 -4
- ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_all.html +1 -1
- ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_progress.html +3 -1
- ipfabric_netbox/templates/ipfabric_netbox/partials/job_logs.html +12 -12
- ipfabric_netbox/tests/test_views.py +2 -2
- ipfabric_netbox/views.py +2 -2
- {ipfabric_netbox-4.3.0b7.dist-info → ipfabric_netbox-4.3.0b9.dist-info}/METADATA +1 -1
- {ipfabric_netbox-4.3.0b7.dist-info → ipfabric_netbox-4.3.0b9.dist-info}/RECORD +13 -12
- {ipfabric_netbox-4.3.0b7.dist-info → ipfabric_netbox-4.3.0b9.dist-info}/WHEEL +0 -0
ipfabric_netbox/__init__.py
CHANGED
ipfabric_netbox/jobs.py
CHANGED
|
@@ -4,7 +4,6 @@ from datetime import timedelta
|
|
|
4
4
|
from core.choices import DataSourceStatusChoices
|
|
5
5
|
from core.choices import JobStatusChoices
|
|
6
6
|
from core.exceptions import SyncError
|
|
7
|
-
from core.models import Job
|
|
8
7
|
from netbox.context_managers import event_tracking
|
|
9
8
|
from rq.timeouts import JobTimeoutException
|
|
10
9
|
from utilities.datetime import local_now
|
|
@@ -36,15 +35,15 @@ def sync_ipfabricsource(job, *args, **kwargs):
|
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
def sync_ipfabric(job, *args, **kwargs):
|
|
39
|
-
|
|
38
|
+
sync = IPFabricSync.objects.get(pk=job.object_id)
|
|
40
39
|
|
|
41
40
|
try:
|
|
42
41
|
job.start()
|
|
43
|
-
|
|
42
|
+
sync.sync(job=job)
|
|
44
43
|
job.terminate()
|
|
45
44
|
except Exception as e:
|
|
46
45
|
job.terminate(status=JobStatusChoices.STATUS_ERRORED)
|
|
47
|
-
IPFabricSync.objects.filter(pk=
|
|
46
|
+
IPFabricSync.objects.filter(pk=sync.pk).update(
|
|
48
47
|
status=DataSourceStatusChoices.FAILED
|
|
49
48
|
)
|
|
50
49
|
if type(e) in (SyncError, JobTimeoutException):
|
|
@@ -52,15 +51,38 @@ def sync_ipfabric(job, *args, **kwargs):
|
|
|
52
51
|
else:
|
|
53
52
|
raise e
|
|
54
53
|
finally:
|
|
55
|
-
if
|
|
56
|
-
new_scheduled_time = local_now() + timedelta(minutes=
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
if sync.interval and not kwargs.get("adhoc"):
|
|
55
|
+
new_scheduled_time = local_now() + timedelta(minutes=sync.interval)
|
|
56
|
+
# We want to create new Job only if scheduled time was before this Job started
|
|
57
|
+
# The current sync might have been changed while this job was running
|
|
58
|
+
sync.refresh_from_db()
|
|
59
|
+
if not sync.scheduled or (sync.scheduled and sync.scheduled > job.started):
|
|
60
|
+
logger.info(
|
|
61
|
+
f"Not scheduling a new job for IPFabricSync {sync.pk} as the scheduled time was changed while the job was running."
|
|
62
|
+
)
|
|
63
|
+
return
|
|
64
|
+
# Update the sync object with the new scheduled time
|
|
65
|
+
# This also triggers the creation of a new Job
|
|
66
|
+
# Running in fake request context to ensure user is set for changelog
|
|
67
|
+
request = NetBoxFakeRequest(
|
|
68
|
+
{
|
|
69
|
+
"META": {},
|
|
70
|
+
"POST": sync.parameters,
|
|
71
|
+
"GET": {},
|
|
72
|
+
"FILES": {},
|
|
73
|
+
"user": sync.user,
|
|
74
|
+
"path": "",
|
|
75
|
+
"id": job.job_id,
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
with event_tracking(request):
|
|
80
|
+
sync.scheduled = new_scheduled_time
|
|
81
|
+
sync.status = DataSourceStatusChoices.QUEUED
|
|
82
|
+
sync.full_clean()
|
|
83
|
+
sync.save()
|
|
84
|
+
logger.info(
|
|
85
|
+
f"Scheduled next sync for IPFabricSync {sync.pk} at {new_scheduled_time}."
|
|
64
86
|
)
|
|
65
87
|
|
|
66
88
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from datetime import timedelta
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from django.db import migrations
|
|
5
|
+
from utilities.datetime import local_now
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from django.apps import apps as apps_type
|
|
9
|
+
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def clean_scheduled_jobs(
|
|
13
|
+
apps: "apps_type", schema_editor: "BaseDatabaseSchemaEditor"
|
|
14
|
+
) -> None:
|
|
15
|
+
Job = apps.get_model("core", "Job")
|
|
16
|
+
IPFabricSync = apps.get_model("ipfabric_netbox", "IPFabricSync")
|
|
17
|
+
ObjectType = apps.get_model("core", "ObjectType")
|
|
18
|
+
|
|
19
|
+
for sync in IPFabricSync.objects.all():
|
|
20
|
+
try:
|
|
21
|
+
scheduled_jobs = Job.objects.filter(
|
|
22
|
+
object_id=sync.id,
|
|
23
|
+
object_type=ObjectType.objects.get_for_model(sync),
|
|
24
|
+
scheduled__isnull=False,
|
|
25
|
+
).order_by("scheduled")
|
|
26
|
+
if not scheduled_jobs.exists():
|
|
27
|
+
continue
|
|
28
|
+
if not sync.scheduled:
|
|
29
|
+
# Delete all scheduled jobs if the sync is not scheduled
|
|
30
|
+
scheduled_jobs.delete()
|
|
31
|
+
continue
|
|
32
|
+
if scheduled_jobs.count() == 1:
|
|
33
|
+
# Only one scheduled job exists, let's update scheduled time on the sync object
|
|
34
|
+
# This does not create a new job since sync is a Faked object in migration
|
|
35
|
+
sync.scheduled = scheduled_jobs.first().scheduled
|
|
36
|
+
sync.full_clean()
|
|
37
|
+
sync.save()
|
|
38
|
+
continue
|
|
39
|
+
# More than one scheduled job exists
|
|
40
|
+
# Find the one that is closest to scheduled + N * interval
|
|
41
|
+
interval = timedelta(minutes=sync.interval)
|
|
42
|
+
elapsed = local_now() - sync.scheduled
|
|
43
|
+
intervals_passed = (elapsed // interval) + 1
|
|
44
|
+
closest_future_scheduled = sync.scheduled + intervals_passed * interval
|
|
45
|
+
closest_job = min(
|
|
46
|
+
scheduled_jobs,
|
|
47
|
+
key=lambda job: abs(job.scheduled - closest_future_scheduled),
|
|
48
|
+
)
|
|
49
|
+
for job in scheduled_jobs:
|
|
50
|
+
if job != closest_job:
|
|
51
|
+
job.delete()
|
|
52
|
+
sync.scheduled = closest_job.scheduled
|
|
53
|
+
sync.full_clean()
|
|
54
|
+
sync.save()
|
|
55
|
+
except Exception as err:
|
|
56
|
+
# Always be safe inside a migration
|
|
57
|
+
print(f"Error cleaning scheduled jobs for IPFabricSync {sync.id}: {err}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Migration(migrations.Migration):
|
|
61
|
+
dependencies = [
|
|
62
|
+
(
|
|
63
|
+
"ipfabric_netbox",
|
|
64
|
+
"0019_alter_ipfabrictransformmap_options_and_more",
|
|
65
|
+
),
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
operations = [
|
|
69
|
+
migrations.RunPython(clean_scheduled_jobs, migrations.RunPython.noop),
|
|
70
|
+
]
|
ipfabric_netbox/models.py
CHANGED
|
@@ -8,6 +8,7 @@ from uuid import uuid4
|
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
10
10
|
from core.choices import DataSourceStatusChoices
|
|
11
|
+
from core.choices import JobStatusChoices
|
|
11
12
|
from core.exceptions import SyncError
|
|
12
13
|
from core.models import Job
|
|
13
14
|
from core.models import ObjectType
|
|
@@ -710,32 +711,56 @@ class IPFabricSync(IPFabricClient, JobsMixin, TagsMixin, ChangeLoggedModel):
|
|
|
710
711
|
pk__in=[tm.pk for tm in maps_by_target.values()]
|
|
711
712
|
)
|
|
712
713
|
|
|
713
|
-
def
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
714
|
+
def delete_scheduled_jobs(self) -> None:
|
|
715
|
+
Job.objects.filter(
|
|
716
|
+
object_type=ObjectType.objects.get_for_model(self),
|
|
717
|
+
object_id=self.pk,
|
|
718
|
+
status__in=[
|
|
719
|
+
JobStatusChoices.STATUS_PENDING,
|
|
720
|
+
JobStatusChoices.STATUS_SCHEDULED,
|
|
721
|
+
],
|
|
722
|
+
).delete()
|
|
723
|
+
|
|
724
|
+
def enqueue_sync_job(self, adhoc=False, user=None) -> Job | None:
|
|
725
|
+
def set_syncing_status():
|
|
726
|
+
self.status = DataSourceStatusChoices.QUEUED
|
|
727
|
+
IPFabricSync.objects.filter(pk=self.pk).update(status=self.status)
|
|
728
|
+
|
|
729
|
+
def sync_snapshots():
|
|
730
|
+
Job.enqueue(
|
|
731
|
+
import_string("ipfabric_netbox.jobs.sync_ipfabricsource"),
|
|
732
|
+
name=f"{self.name} Snapshot Sync (Pre Ingestion)",
|
|
733
|
+
instance=self.snapshot_data.source,
|
|
734
|
+
user=self.user,
|
|
735
|
+
)
|
|
724
736
|
|
|
725
737
|
# Enqueue a sync job
|
|
726
738
|
if not user:
|
|
727
739
|
user = self.user
|
|
728
740
|
|
|
729
|
-
if not adhoc
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
741
|
+
if not adhoc:
|
|
742
|
+
if self.scheduled:
|
|
743
|
+
# We want to schedule a recurring Job
|
|
744
|
+
# We need to replace the old scheduled Job to make sure it has current context
|
|
745
|
+
self.delete_scheduled_jobs()
|
|
746
|
+
set_syncing_status()
|
|
747
|
+
sync_snapshots()
|
|
748
|
+
job = Job.enqueue(
|
|
749
|
+
import_string("ipfabric_netbox.jobs.sync_ipfabric"),
|
|
750
|
+
name=f"{self.name} - (scheduled)",
|
|
751
|
+
instance=self,
|
|
752
|
+
user=self.user,
|
|
753
|
+
schedule_at=self.scheduled,
|
|
754
|
+
interval=self.interval,
|
|
755
|
+
)
|
|
756
|
+
else:
|
|
757
|
+
# There should be no scheduled Job anymore, clean it up
|
|
758
|
+
self.delete_scheduled_jobs()
|
|
759
|
+
job = None
|
|
760
|
+
else:
|
|
761
|
+
# Start adhoc job immediately
|
|
762
|
+
set_syncing_status()
|
|
763
|
+
sync_snapshots()
|
|
739
764
|
job = Job.enqueue(
|
|
740
765
|
import_string("ipfabric_netbox.jobs.sync_ipfabric"),
|
|
741
766
|
instance=self,
|
|
@@ -872,7 +897,7 @@ class IPFabricSync(IPFabricClient, JobsMixin, TagsMixin, ChangeLoggedModel):
|
|
|
872
897
|
self.logger.log_info("Auto Merging Ingestion", obj=ingestion)
|
|
873
898
|
logger.info("Auto Merging Ingestion")
|
|
874
899
|
try:
|
|
875
|
-
ingestion.enqueue_merge_job(user=user)
|
|
900
|
+
ingestion.enqueue_merge_job(user=user, remove_branch=True)
|
|
876
901
|
self.logger.log_info("Auto Merge Job Enqueued", obj=ingestion)
|
|
877
902
|
logger.info("Auto Merge Job Enqueued")
|
|
878
903
|
except NameError:
|
|
@@ -937,6 +962,9 @@ class IPFabricIngestion(JobsMixin, models.Model):
|
|
|
937
962
|
)
|
|
938
963
|
|
|
939
964
|
def get_logs(self):
|
|
965
|
+
if not self.job:
|
|
966
|
+
# The Job is deleted by manual action
|
|
967
|
+
return {}
|
|
940
968
|
if self.job.data:
|
|
941
969
|
job_results = self.job.data
|
|
942
970
|
else:
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
{% custom_links object %}
|
|
16
16
|
</div>
|
|
17
17
|
{% if perms.core.sync_datasource %}
|
|
18
|
-
{% if object.sync.ready_for_sync %}
|
|
18
|
+
{% if object.sync.ready_for_sync and object.branch and object.branch.status != "merged" %}
|
|
19
19
|
<a href="#"
|
|
20
20
|
hx-get="{% url 'plugins:ipfabric_netbox:ipfabricingestion_merge' pk=object.pk %}"
|
|
21
21
|
hx-target="#htmx-modal-content"
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
</tr>
|
|
70
70
|
<tr>
|
|
71
71
|
<th scope="row">Job Object</th>
|
|
72
|
-
<td
|
|
72
|
+
<td>{% if object.job %}<a href="{% url 'core:job' pk=object.job.pk %}">{{ object.job }}</a>{% else %}{{ ""|placeholder }}{% endif %}</td>
|
|
73
73
|
</tr>
|
|
74
74
|
<tr>
|
|
75
75
|
<th scope="row">Ingestion Status</th>
|
|
@@ -96,14 +96,14 @@
|
|
|
96
96
|
{% include 'ipfabric_netbox/partials/ingestion_statistics.html' with object=object %}
|
|
97
97
|
</div>
|
|
98
98
|
<div id="ingestion_progress" hx-swap-oob="true">
|
|
99
|
-
{% include 'ipfabric_netbox/partials/ingestion_progress.html' %}
|
|
99
|
+
{% include 'ipfabric_netbox/partials/ingestion_progress.html' with job=object.job %}
|
|
100
100
|
</div>
|
|
101
101
|
<!-- {% include 'inc/panels/related_objects.html' %} -->
|
|
102
102
|
{% include 'inc/panels/custom_fields.html' %}
|
|
103
103
|
{% plugin_right_page object %}
|
|
104
104
|
</div>
|
|
105
105
|
<div class="row mb-3">
|
|
106
|
-
<div class="col col-md-12" {% if not object.job.completed %} hx-get="{% url 'plugins:ipfabric_netbox:ipfabricingestion_logs' pk=object.pk %}?type=info"
|
|
106
|
+
<div class="col col-md-12" {% if object.job and not object.job.completed %} hx-get="{% url 'plugins:ipfabric_netbox:ipfabricingestion_logs' pk=object.pk %}?type=info"
|
|
107
107
|
hx-trigger="every 5s" hx-target="#ingestion_logs" hx-select="#ingestion_logs" hx-select-oob="#ingestion_status:innerHTML,#ingestion_progress:innerHTML,#ingestion_statistics:innerHTML,#object_tabs:innerHTML"
|
|
108
108
|
hx-swap="innerHTML" {% endif %}>
|
|
109
109
|
<div id="ingestion_logs">{% include 'ipfabric_netbox/partials/job_logs.html' with job=object.job %}</div>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
{% include 'ipfabric_netbox/partials/ingestion_status.html' with object=object %}
|
|
9
9
|
</div>
|
|
10
10
|
<div id="ingestion_progress" hx-swap-oob="true">
|
|
11
|
-
{% include 'ipfabric_netbox/partials/ingestion_progress.html' %}
|
|
11
|
+
{% include 'ipfabric_netbox/partials/ingestion_progress.html' with job=job %}
|
|
12
12
|
</div>
|
|
13
13
|
<div id="ingestion_logs">
|
|
14
14
|
{% include 'ipfabric_netbox/partials/job_logs.html' with job_results=job_results job=job %}
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
<div class="card">
|
|
3
3
|
<h5 class="card-header">Progress</h5>
|
|
4
4
|
<div class="card-body">
|
|
5
|
-
{% if
|
|
5
|
+
{% if not job %}
|
|
6
|
+
Cannot show progress, no sync Job exists anymore.
|
|
7
|
+
{% elif statistics %}
|
|
6
8
|
<table class="table table-hover attr-table">
|
|
7
9
|
{% for model, util in statistics.items %}
|
|
8
10
|
<tr>
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
{% load helpers %}
|
|
3
3
|
|
|
4
4
|
<p>
|
|
5
|
-
{% if job.started %}
|
|
6
|
-
Started: <strong>{{ job.started|isodatetime }}</strong>
|
|
7
|
-
{% elif job.scheduled %}
|
|
8
|
-
Scheduled for: <strong>{{ job.scheduled|isodatetime }}</strong> ({{ job.scheduled|naturaltime }})
|
|
9
|
-
{%
|
|
10
|
-
Created: <strong>{{ job.created|isodatetime }}</strong>
|
|
11
|
-
{% endif %}
|
|
12
|
-
{% if job.completed %}
|
|
13
|
-
Duration: <strong>{{ job.duration }}</strong>
|
|
14
|
-
{% endif %}
|
|
5
|
+
{% if job.started %}
|
|
6
|
+
Started: <strong>{{ job.started|isodatetime }}</strong>
|
|
7
|
+
{% elif job.scheduled %}
|
|
8
|
+
Scheduled for: <strong>{{ job.scheduled|isodatetime }}</strong> ({{ job.scheduled|naturaltime }})
|
|
9
|
+
{% elif job %}
|
|
10
|
+
Created: <strong>{{ job.created|isodatetime }}</strong>
|
|
11
|
+
{% endif %}
|
|
12
|
+
{% if job.completed %}
|
|
13
|
+
Duration: <strong>{{ job.duration }}</strong>
|
|
14
|
+
{% endif %}
|
|
15
15
|
<span id="pending-result-label">{% badge job.get_status_display job.get_status_color %}</span>
|
|
16
16
|
</p>
|
|
17
|
-
{% if not job.completed %}
|
|
18
|
-
{% include 'ipfabric_netbox/inc/logs_pending.html' %}
|
|
17
|
+
{% if job and not job.completed %}
|
|
18
|
+
{% include 'ipfabric_netbox/inc/logs_pending.html' %}
|
|
19
19
|
{% endif %}
|
|
20
20
|
<div class="card">
|
|
21
21
|
<h5 class="card-header">Sync Results</h5>
|
|
@@ -719,7 +719,7 @@ class IPFabricSyncTestCase(
|
|
|
719
719
|
|
|
720
720
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
721
721
|
def test_get_htmx_request(self):
|
|
722
|
-
instance = self._get_queryset().
|
|
722
|
+
instance = self._get_queryset().last()
|
|
723
723
|
# Try GET with HTMX
|
|
724
724
|
response = self.client.get(
|
|
725
725
|
instance.get_absolute_url(), **{"HTTP_HX-Request": "true"}
|
|
@@ -1628,7 +1628,7 @@ class IPFabricIngestionTestCase(
|
|
|
1628
1628
|
self.assertHttpStatus(response, 200)
|
|
1629
1629
|
|
|
1630
1630
|
# Verify the response contains expected elements
|
|
1631
|
-
self.assertContains(response, "
|
|
1631
|
+
self.assertContains(response, "Ingestion progress pending...")
|
|
1632
1632
|
|
|
1633
1633
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
|
1634
1634
|
def test_get_logs_htmx(self):
|
ipfabric_netbox/views.py
CHANGED
|
@@ -938,7 +938,7 @@ class IPFabricIngestionLogView(LoginRequiredMixin, View):
|
|
|
938
938
|
ingestion = annotate_statistics(IPFabricIngestion.objects).get(pk=ingestion_id)
|
|
939
939
|
data = ingestion.get_statistics()
|
|
940
940
|
data["object"] = ingestion
|
|
941
|
-
data["job"] = ingestion.
|
|
941
|
+
data["job"] = ingestion.job
|
|
942
942
|
|
|
943
943
|
if request.htmx:
|
|
944
944
|
response = render(
|
|
@@ -946,7 +946,7 @@ class IPFabricIngestionLogView(LoginRequiredMixin, View):
|
|
|
946
946
|
self.template_name,
|
|
947
947
|
data,
|
|
948
948
|
)
|
|
949
|
-
if ingestion.job.completed:
|
|
949
|
+
if not ingestion.job or ingestion.job.completed:
|
|
950
950
|
response["HX-Refresh"] = "true"
|
|
951
951
|
return response
|
|
952
952
|
return render(request, self.template_name, data)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ipfabric_netbox/__init__.py,sha256=
|
|
1
|
+
ipfabric_netbox/__init__.py,sha256=CgoIoRyEpMEu6R1YM-wn9Gjk3vZF8zSn7jbrjS4DDUY,674
|
|
2
2
|
ipfabric_netbox/api/__init__.py,sha256=XRclTGWVR0ZhAAwgYul5Wm_loug5_hUjEumbLQEwKYM,47
|
|
3
3
|
ipfabric_netbox/api/serializers.py,sha256=lr_PWG0tqAxaKtkIIm8Gx2B-tn9yENQIfKY9cvu8Cco,6581
|
|
4
4
|
ipfabric_netbox/api/urls.py,sha256=1fXXVTxNY5E64Nfz6b7zXD9bZI3FcefuxAWKMe0w_QU,1240
|
|
@@ -13,7 +13,7 @@ ipfabric_netbox/graphql/enums.py,sha256=QFhwiwUKJekxQfsOGk_-70_WnkzrKEP_zIBMrin0
|
|
|
13
13
|
ipfabric_netbox/graphql/filters.py,sha256=B8xy9r9a18vWfV6a6tHXAN1FUcoxI6MOrbsdNmzusNI,12991
|
|
14
14
|
ipfabric_netbox/graphql/schema.py,sha256=5UVHA1hHRvho5eLuuS-HLXTVTbxpUUx68ovG03gumGE,3209
|
|
15
15
|
ipfabric_netbox/graphql/types.py,sha256=8RxdxiA-WnoaWSzh-tUJCuZBYGmd6QjfJiJcLirRMKY,5961
|
|
16
|
-
ipfabric_netbox/jobs.py,sha256=
|
|
16
|
+
ipfabric_netbox/jobs.py,sha256=rFQuuc_6WVZlJ2EGDDj2ml14L4JeFneSSTiKA8N1SUg,4189
|
|
17
17
|
ipfabric_netbox/migrations/0001_initial.py,sha256=VphxkWL6QzWq2tcrdXlog718xQtiEGizKwS830z_fOs,13824
|
|
18
18
|
ipfabric_netbox/migrations/0001_initial_squashed_0013_switch_to_branching_plugin.py,sha256=OvofuA8ImeJmjrbtCrZPcRxAUWx2Ww4DUXLBZYsy6qE,21381
|
|
19
19
|
ipfabric_netbox/migrations/0002_ipfabricsnapshot_status.py,sha256=xQpouHjOutyj6riN2B592njzSvz_icpkUbo5W7nWLYw,431
|
|
@@ -34,8 +34,9 @@ ipfabric_netbox/migrations/0016_tags_and_changelog_for_snapshots.py,sha256=XqftT
|
|
|
34
34
|
ipfabric_netbox/migrations/0017_ipfabricsync_update_custom_fields.py,sha256=IVbAL2WdigYT40sXN0A8K3HweJ_O4QqyzjB06TbkG5E,447
|
|
35
35
|
ipfabric_netbox/migrations/0018_remove_type_field.py,sha256=ffxW6IS3BLCbvM5M9DbDb_x6spMmRxnV1iq8IuXxMGw,385
|
|
36
36
|
ipfabric_netbox/migrations/0019_alter_ipfabrictransformmap_options_and_more.py,sha256=ieDVedt9KpJBicAiC3kdZXzHeos12N0L9EdRXKmIVgY,501
|
|
37
|
+
ipfabric_netbox/migrations/0020_clean_scheduled_jobs.py,sha256=zjCVKnCWTKYYkpVRwHjqRIRR2j6ALSKXYMfraRjNu7Y,2652
|
|
37
38
|
ipfabric_netbox/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
ipfabric_netbox/models.py,sha256=
|
|
39
|
+
ipfabric_netbox/models.py,sha256=g6EnrCp714aDig7Rh3_WRe1CHIwpSMV1YLWJexUJL2U,38222
|
|
39
40
|
ipfabric_netbox/navigation.py,sha256=2dEJ_wKHb52Tl0FOV1TH3JbxRe8YZ56ewrTsBFGKpCg,2210
|
|
40
41
|
ipfabric_netbox/signals.py,sha256=cGa5PVD2i24pGXiVNfbu6ruIDqPVdwKQHTSWe9Ura84,1838
|
|
41
42
|
ipfabric_netbox/tables.py,sha256=BpPmL6-KClX16Ol_PIADyOx9NtDR9oauXH5iO4GeSoI,9008
|
|
@@ -51,7 +52,7 @@ ipfabric_netbox/templates/ipfabric_netbox/inc/snapshotdata.html,sha256=1ItOCPjjp
|
|
|
51
52
|
ipfabric_netbox/templates/ipfabric_netbox/inc/transform_map_field_map.html,sha256=mRU-rBweVFvaPFHbVYPw7vcYyXiVaXCOkeHm7xWdKPA,500
|
|
52
53
|
ipfabric_netbox/templates/ipfabric_netbox/inc/transform_map_relationship_map.html,sha256=qyuG_EXZMGUscA3sv_6WGSrf_bR7JTRlKyMYf6EYyo4,504
|
|
53
54
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabric_table.html,sha256=TsF34lK2CyDsMxlFTk--2lF_0AxYM614eKmkgYAbJ-k,1629
|
|
54
|
-
ipfabric_netbox/templates/ipfabric_netbox/ipfabricingestion.html,sha256=
|
|
55
|
+
ipfabric_netbox/templates/ipfabric_netbox/ipfabricingestion.html,sha256=ymqTB9JEk0AFncK5kz8yStHWCD_IMNKlbgyqu_qon7g,4585
|
|
55
56
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabricsnapshot.html,sha256=hj8ORs_4mM_xTjmw3McHN-da5seC8nbbkzobn0f1TSc,3482
|
|
56
57
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabricsource.html,sha256=DQOA2TA7f1nI5YpxXthS1VzjIU1kMZus37l6bYSCauE,3869
|
|
57
58
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html,sha256=dt8HYuHCzIN4otLS9QK3e1aES14isFI-1jyp8jrENXU,4616
|
|
@@ -59,11 +60,11 @@ ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap.html,sha256=qFo_K
|
|
|
59
60
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_list.html,sha256=p8zqn0-B6mawSUM3zQrus6dsKUM5SRBTO0X94pLboX8,452
|
|
60
61
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_restore.html,sha256=TV7gAZWtSd-c7mzOen_nv7Z8MZr2Vw8vkHP4zW9au4w,2580
|
|
61
62
|
ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmapgroup.html,sha256=H3uvjA4PdJq5uX2kizdHV1pAxwcPpyfc9IbJi1ZK5-k,975
|
|
62
|
-
ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_all.html,sha256=
|
|
63
|
-
ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_progress.html,sha256=
|
|
63
|
+
ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_all.html,sha256=ZstgG3MJbd8WAOcGUKEpt4CSjIInhF14wgVgqSc1oAs,675
|
|
64
|
+
ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_progress.html,sha256=tb9JAc9GjPd05F1RQdRrfrDwSQMWlcbbQOrQCXedQWs,680
|
|
64
65
|
ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_statistics.html,sha256=_KtbxZQlIa_141OQSIAvSsMMfZRkNj27kJqrYHuLt7Y,867
|
|
65
66
|
ipfabric_netbox/templates/ipfabric_netbox/partials/ingestion_status.html,sha256=qYXe-V-kQn1INqCHLSSpdrzXJ_IIt84AgCgAGwqpNbs,178
|
|
66
|
-
ipfabric_netbox/templates/ipfabric_netbox/partials/job_logs.html,sha256=
|
|
67
|
+
ipfabric_netbox/templates/ipfabric_netbox/partials/job_logs.html,sha256=THiEs8wYMvEn8y0XGhxX7rj3w466CkDhaEzc4CxgGLY,1694
|
|
67
68
|
ipfabric_netbox/templates/ipfabric_netbox/partials/object_tabs.html,sha256=3xbGy38Y1RH13bVPlcyj5L6J_FM-mOW1y0fx54hj1xE,364
|
|
68
69
|
ipfabric_netbox/templates/ipfabric_netbox/partials/sync_last_ingestion.html,sha256=3v6tC88xE5cic9l9lQw7Msawoq-AW2oo2odd-osGv50,179
|
|
69
70
|
ipfabric_netbox/templates/static/ipfabric_netbox/css/rack.css,sha256=z1H-RmmsqF2pGdhn5J64TMFiccy62xZUHHlCRd8fJrQ,118
|
|
@@ -74,14 +75,14 @@ ipfabric_netbox/tests/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
74
75
|
ipfabric_netbox/tests/api/test_api.py,sha256=9o9k4kfnT3Zz9Hg0qnI0_XASt6pi5BCZQ3RhBjsb_iE,35215
|
|
75
76
|
ipfabric_netbox/tests/test_forms.py,sha256=C8giV6E3PbMB9_864C12ebvfQ3Vlvdn39VIQQSP6GV8,61566
|
|
76
77
|
ipfabric_netbox/tests/test_models.py,sha256=FFrIT5xxv_yvujKpxGjRJPNPBDF2Pqi8zbY0vxuJeQs,16043
|
|
77
|
-
ipfabric_netbox/tests/test_views.py,sha256=
|
|
78
|
+
ipfabric_netbox/tests/test_views.py,sha256=OhPoRrXA8lEzjTktjbm3I8LkByBHDXA45z9gOEspho4,87784
|
|
78
79
|
ipfabric_netbox/urls.py,sha256=qF2BzZEDnPRd3opFaRfiMdaarYKFfv69iMaAbU2rsBU,2702
|
|
79
80
|
ipfabric_netbox/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
81
|
ipfabric_netbox/utilities/ipfutils.py,sha256=wFmL5oriuF-is1ZlrIcLmoeYUY5ih-CA9weRQrx5AiA,31885
|
|
81
82
|
ipfabric_netbox/utilities/logging.py,sha256=GYknjocMN6LQ2873_az3y0RKm29TCXaWviUIIneH-x0,3445
|
|
82
83
|
ipfabric_netbox/utilities/nbutils.py,sha256=kFBEiJOGvr_49hJWCS2duXojx2-A9kVk0Xp_vj0ohfs,2641
|
|
83
84
|
ipfabric_netbox/utilities/transform_map.py,sha256=GpM_7Mm6FE0qV2qbyj4YfDn0l-JkeeEHQOZkNVSSHk4,2391
|
|
84
|
-
ipfabric_netbox/views.py,sha256=
|
|
85
|
-
ipfabric_netbox-4.3.
|
|
86
|
-
ipfabric_netbox-4.3.
|
|
87
|
-
ipfabric_netbox-4.3.
|
|
85
|
+
ipfabric_netbox/views.py,sha256=JcXvoLo8JQ0PUyvUwi1tZQgrxw9okKBlocsIUKoGAbo,44758
|
|
86
|
+
ipfabric_netbox-4.3.0b9.dist-info/METADATA,sha256=HdBydWNVKafz4hTNweGmrZ5bcDsVQLGAsd1rZM-abi0,4754
|
|
87
|
+
ipfabric_netbox-4.3.0b9.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
88
|
+
ipfabric_netbox-4.3.0b9.dist-info/RECORD,,
|
|
File without changes
|