14438 script job mapping

This commit is contained in:
Arthur 2024-02-06 09:32:19 -08:00
parent fc890e36af
commit 6930e441ae
8 changed files with 61 additions and 36 deletions

View File

@ -8,14 +8,19 @@ def update_scripts(apps, schema_editor):
from extras.models import ScriptModule
ScriptModuleNew = apps.get_model('extras', 'ScriptModule')
Script = apps.get_model('extras', 'Script')
ContentType = apps.get_model('contenttypes', 'ContentType')
ct = ContentType.objects.get(app_label='extras', model='script')
for module in ScriptModule.objects.all():
for script in module.get_module_scripts.keys():
Script.objects.create(
obj = Script.objects.create(
name=script,
module=ScriptModuleNew.objects.get(file_root=module.file_root, file_path=module.file_path),
)
# update all jobs associated with this module/name to point to the new script obj
module.jobs.filter(name=name).update(object_type=ct, object_id=obj.id)
class Migration(migrations.Migration):
@ -35,6 +40,10 @@ class Migration(migrations.Migration):
'ordering': ('name', 'pk'),
},
),
migrations.AddConstraint(
model_name='script',
constraint=models.UniqueConstraint(fields=('name', 'module'), name='extras_script_unique_name_module'),
),
migrations.RunPython(
code=update_scripts,
reverse_code=migrations.RunPython.noop

View File

@ -21,7 +21,7 @@ __all__ = (
logger = logging.getLogger('netbox.data_backends')
class Script(EventRulesMixin, models.Model):
class Script(EventRulesMixin, JobsMixin, models.Model):
name = models.CharField(
verbose_name=_('name'),
max_length=79,
@ -37,11 +37,24 @@ class Script(EventRulesMixin, models.Model):
class Meta:
ordering = ('name', 'pk')
constraints = (
models.UniqueConstraint(
fields=('name', 'module'),
name='%(app_label)s_%(class)s_unique_name_module'
),
)
verbose_name = _('script')
verbose_name_plural = _('scripts')
@cached_property
def python_class(self):
return self.module.get_module_scripts.get(self.name)
def get_jobs(self):
return self.module.jobs.filter(
name=self.name
)
class ScriptModuleManager(models.Manager.from_queryset(RestrictedQuerySet)):

View File

@ -130,9 +130,9 @@ urlpatterns = [
path('scripts/add/', views.ScriptModuleCreateView.as_view(), name='scriptmodule_add'),
path('scripts/results/<int:job_pk>/', views.ScriptResultView.as_view(), name='script_result'),
path('scripts/<int:pk>/', include(get_model_urls('extras', 'scriptmodule'))),
path('scripts/<str:module>/<str:name>/', views.ScriptView.as_view(), name='script'),
path('scripts/<str:module>/<str:name>/source/', views.ScriptSourceView.as_view(), name='script_source'),
path('scripts/<str:module>/<str:name>/jobs/', views.ScriptJobsView.as_view(), name='script_jobs'),
path('scripts/class/<int:pk>/', views.ScriptView.as_view(), name='script'),
path('scripts/class/<int:pk>/source/', views.ScriptSourceView.as_view(), name='script_source'),
path('scripts/class/<int:pk>/jobs/', views.ScriptJobsView.as_view(), name='script_jobs'),
# Markdown
path('render/markdown/', views.RenderMarkdownView.as_view(), name="render_markdown"),

View File

@ -1226,27 +1226,28 @@ class ScriptView(ContentTypePermissionRequiredMixin, View):
def get_required_permission(self):
return 'extras.view_script'
def get(self, request, module, name):
module = get_script_module(module, request)
script = module.scripts[name]()
jobs = module.get_jobs(script.class_name)
form = script.as_form(initial=normalize_querydict(request.GET))
def get(self, request, pk):
script = Script.objects.get(pk=pk)
script_class = script.python_class()
jobs = script.get_jobs()
form = script_class.as_form(initial=normalize_querydict(request.GET))
return render(request, 'extras/script.html', {
'job_count': jobs.count(),
'module': module,
'module': script.module,
'script': script,
'script_class': script_class,
'form': form,
})
def post(self, request, module, name):
def post(self, request, pk):
if not request.user.has_perm('extras.run_script'):
return HttpResponseForbidden()
module = get_script_module(module, request)
script = module.scripts[name]()
jobs = module.get_jobs(script.class_name)
form = script.as_form(request.POST, request.FILES)
script = Script.objects.get(pk=pk)
script_class = script.python_class()
jobs = script.get_jobs()
form = script_class.as_form(request.POST, request.FILES)
# Allow execution only if RQ worker process is running
if not get_workers_for_queue('default'):
@ -1255,8 +1256,8 @@ class ScriptView(ContentTypePermissionRequiredMixin, View):
elif form.is_valid():
job = Job.enqueue(
run_script,
instance=module,
name=script.class_name,
instance=script.module,
name=script_class.class_name,
user=request.user,
schedule_at=form.cleaned_data.pop('_schedule_at'),
interval=form.cleaned_data.pop('_interval'),
@ -1270,8 +1271,9 @@ class ScriptView(ContentTypePermissionRequiredMixin, View):
return render(request, 'extras/script.html', {
'job_count': jobs.count(),
'module': module,
'module': script.module,
'script': script,
'script_class': script_class,
'form': form,
})
@ -1281,15 +1283,16 @@ class ScriptSourceView(ContentTypePermissionRequiredMixin, View):
def get_required_permission(self):
return 'extras.view_script'
def get(self, request, module, name):
module = get_script_module(module, request)
script = module.scripts[name]()
jobs = module.get_jobs(script.class_name)
def get(self, request, pk):
script = Script.objects.get(pk=pk)
script_class = script.python_class()
jobs = script.get_jobs()
return render(request, 'extras/script/source.html', {
'job_count': jobs.count(),
'module': module,
'module': script.module,
'script': script,
'script_class': script_class,
'tab': 'source',
})
@ -1299,10 +1302,10 @@ class ScriptJobsView(ContentTypePermissionRequiredMixin, View):
def get_required_permission(self):
return 'extras.view_script'
def get(self, request, module, name):
module = get_script_module(module, request)
script = module.scripts[name]()
jobs = module.get_jobs(script.class_name)
def get(self, request, pk):
script = Script.objects.get(pk=pk)
script_class = script.python_class()
jobs = script.get_jobs()
jobs_table = JobTable(
data=jobs,
@ -1313,7 +1316,7 @@ class ScriptJobsView(ContentTypePermissionRequiredMixin, View):
return render(request, 'extras/script/jobs.html', {
'job_count': jobs.count(),
'module': module,
'module': script.module,
'script': script,
'table': jobs_table,
'tab': 'jobs',

View File

@ -17,7 +17,7 @@
{% csrf_token %}
<div class="field-group my-4">
{# Render grouped fields according to declared fieldsets #}
{% for group, fields in script.get_fieldsets %}
{% for group, fields in script_class.get_fieldsets %}
{% if fields %}
<div class="field-group mb-5">
<div class="row">

View File

@ -26,13 +26,13 @@
{% block tabs %}
<ul class="nav nav-tabs">
<li class="nav-item" role="presentation">
<a class="nav-link{% if not tab %} active{% endif %}" href="{% url 'extras:script' module=script.module name=script.class_name %}">{% trans "Script" %}</a>
<a class="nav-link{% if not tab %} active{% endif %}" href="{% url 'extras:script' script.id %}">{% trans "Script" %}</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link{% if tab == 'source' %} active{% endif %}" href="{% url 'extras:script_source' module=script.module name=script.class_name %}">{% trans "Source" %}</a>
<a class="nav-link{% if tab == 'source' %} active{% endif %}" href="{% url 'extras:script_source' script.id %}">{% trans "Source" %}</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link{% if tab == 'jobs' %} active{% endif %}" href="{% url 'extras:script_jobs' module=script.module name=script.class_name %}">
<a class="nav-link{% if tab == 'jobs' %} active{% endif %}" href="{% url 'extras:script_jobs' script.id %}">
{% trans "Jobs" %} {% badge job_count %}
</a>
</li>

View File

@ -1,6 +1,6 @@
{% extends 'extras/script/base.html' %}
{% block content %}
<code class="h6 my-3 d-block">{{ script.filename }}</code>
<pre class="block">{{ script.source }}</pre>
<code class="h6 my-3 d-block">{{ script_class.filename }}</code>
<pre class="block">{{ script_class.source }}</pre>
{% endblock %}

View File

@ -56,7 +56,7 @@
{% for script in module.scripts.all %}
<tr>
<td>
<a href="{% url 'extras:script' module=module.python_name name=script.name %}" name="script.{{ script.name }}">{{ script.python_class.name }}</a>
<a href="{% url 'extras:script' script.id %}" name="script.{{ script.name }}">{{ script.python_class.name }}</a>
</td>
<td>
{{ script.python_class.Meta.description|markdown|placeholder }}