Skip to content

Commit 4e12a13

Browse files
3.0.1
### Changelog: * Feature(backend): History ``inventory`` field now has value of ``arg_shown_on_history_as_inventory`` of execution plugin. * Fix(backend): Migrate initiator fields to new model instances. See merge request polemarch/ce!305
2 parents cef8d38 + 4138837 commit 4e12a13

File tree

7 files changed

+404
-57
lines changed

7 files changed

+404
-57
lines changed

doc/api_schema.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ info:
7070
application: 3.0.0
7171
library: 3.0.0
7272
vstutils: 5.4.0
73-
django: 4.1.6
73+
django: 4.1.7
7474
djangorestframework: 3.14.0
7575
drf_yasg: 1.21.5
7676
ansible: 2.9.27
@@ -13766,7 +13766,7 @@ definitions:
1376613766
model:
1376713767
$ref: '#/definitions/AnsiblePlaybook'
1376813768
value_field: playbook
13769-
view_field: name
13769+
view_field: playbook
1377013770
usePrefetch: true
1377113771
args:
1377213772
title: Args
@@ -15274,7 +15274,7 @@ definitions:
1527415274
model:
1527515275
$ref: '#/definitions/AnsiblePlaybook'
1527615276
value_field: playbook
15277-
view_field: name
15277+
view_field: playbook
1527815278
usePrefetch: true
1527915279
args:
1528015280
title: Args
@@ -15513,7 +15513,7 @@ definitions:
1551315513
model:
1551415514
$ref: '#/definitions/AnsiblePlaybook'
1551515515
value_field: playbook
15516-
view_field: name
15516+
view_field: playbook
1551715517
usePrefetch: true
1551815518
args:
1551915519
title: Args
@@ -16032,7 +16032,7 @@ definitions:
1603216032
model:
1603316033
$ref: '#/definitions/AnsiblePlaybook'
1603416034
value_field: playbook
16035-
view_field: name
16035+
view_field: playbook
1603616036
usePrefetch: true
1603716037
args:
1603816038
title: Args

polemarch/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@
3131
"VST_ROOT_URLCONF": os.getenv("VST_ROOT_URLCONF", 'vstutils.urls'),
3232
}
3333

34-
__version__ = "3.0.0"
34+
__version__ = "3.0.1"
3535

3636
prepare_environment(**default_settings)

polemarch/main/migrations/0003_v3_migrate_data_to_new_models.py

Lines changed: 115 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,22 @@ def to_template_data(option):
9191

9292
def to_options_data(options_qs):
9393
return {
94-
option.name: to_template_data(option)
94+
slugify(option.name): to_template_data(option)
9595
for option in options_qs
9696
}
9797

9898

9999
def migrate_templates_data_direct(apps, schema_editor):
100100
Template = apps.get_model('main', 'Template')
101101
PeriodicTask = apps.get_model('main', 'PeriodicTask')
102+
History = apps.get_model('main', 'History')
102103

103104
ExecutionTemplate = apps.get_model('main', 'ExecutionTemplate')
104105
ExecutionTemplateOption = apps.get_model('main', 'ExecutionTemplateOption')
105106
TemplatePeriodicTask = apps.get_model('main', 'TemplatePeriodicTask')
106107

107108
db_alias = schema_editor.connection.alias
109+
history_to_update = []
108110

109111
for old_template in Template.objects.all():
110112
new_template = ExecutionTemplate.objects.using(db_alias).create(
@@ -129,24 +131,55 @@ def migrate_templates_data_direct(apps, schema_editor):
129131
for old_option_key, old_option_value in json.loads(old_template.options_data or '{}').items()
130132
]
131133

132-
ExecutionTemplateOption.objects.using(db_alias).bulk_create([default_option, *other_options])
133-
134-
if old_template.periodic_task.exists():
135-
TemplatePeriodicTask.objects.using(db_alias).bulk_create([
136-
TemplatePeriodicTask(
137-
name=old_periodic_task.name,
138-
template_option=default_option if not old_periodic_task.template_opt else [
139-
option for option in other_options
140-
if slugify(option.name) == old_periodic_task.template_opt
141-
][0],
142-
notes=old_periodic_task.notes,
143-
type=old_periodic_task.type,
144-
schedule=old_periodic_task.schedule,
145-
enabled=old_periodic_task.enabled,
146-
save_result=old_periodic_task.save_result,
147-
)
148-
for old_periodic_task in old_template.periodic_task.all()
149-
])
134+
other_options_created = ExecutionTemplateOption.objects.using(db_alias).bulk_create(
135+
[default_option, *other_options]
136+
)
137+
138+
history_to_update_qs = History.objects \
139+
.using(db_alias) \
140+
.filter(initiator_type='template', initiator=old_template.id)
141+
for history in history_to_update_qs:
142+
history.initiator = new_template.id
143+
options = json.loads(history.json_options)
144+
old_template_option = options.get('template_option')
145+
if old_template_option is None:
146+
options['template_option'] = str(default_option.id)
147+
else:
148+
try:
149+
new_option = [
150+
option for option in other_options_created
151+
if slugify(option.name) == old_template_option
152+
][0]
153+
options['template_option'] = str(new_option.id)
154+
except IndexError:
155+
pass
156+
history.json_options = json.dumps(options)
157+
history_to_update.append(history)
158+
159+
for old_periodic_task in old_template.periodic_task.all():
160+
new_periodic_task = TemplatePeriodicTask.objects.using(db_alias).create(
161+
name=old_periodic_task.name,
162+
template_option=default_option if not old_periodic_task.template_opt else [
163+
option for option in other_options
164+
if slugify(option.name) == old_periodic_task.template_opt
165+
][0],
166+
notes=old_periodic_task.notes,
167+
type=old_periodic_task.type,
168+
schedule=old_periodic_task.schedule,
169+
enabled=old_periodic_task.enabled,
170+
save_result=old_periodic_task.save_result,
171+
)
172+
173+
history_to_update_qs = History.objects \
174+
.using(db_alias) \
175+
.filter(initiator_type='scheduler', initiator=old_periodic_task.id)
176+
for history in history_to_update_qs:
177+
history.initiator = new_periodic_task.id
178+
history.json_options = json.dumps({
179+
'template': new_periodic_task.template_option.template.id,
180+
'template_option': str(new_periodic_task.template_option.id),
181+
})
182+
history_to_update.append(history)
150183

151184
for old_periodic_task in PeriodicTask.objects.filter(template_id=None):
152185
variables = {}
@@ -177,7 +210,7 @@ def migrate_templates_data_direct(apps, schema_editor):
177210
inventory=old_periodic_task._inventory_id or old_periodic_task.inventory_file),
178211
template=new_template,
179212
)
180-
TemplatePeriodicTask.objects.using(db_alias).create(
213+
new_periodic_task = TemplatePeriodicTask.objects.using(db_alias).create(
181214
name=old_periodic_task.name,
182215
template_option=default_option,
183216
notes='',
@@ -187,10 +220,24 @@ def migrate_templates_data_direct(apps, schema_editor):
187220
save_result=old_periodic_task.save_result,
188221
)
189222

223+
history_to_update_qs = History.objects \
224+
.using(db_alias) \
225+
.filter(initiator_type='scheduler', initiator=old_periodic_task.id)
226+
for history in history_to_update_qs:
227+
history.initiator = new_periodic_task.id
228+
history.json_options = json.dumps({
229+
'template': new_periodic_task.template_option.template.id,
230+
'template_option': str(new_periodic_task.template_option.id),
231+
})
232+
history_to_update.append(history)
233+
234+
History.objects.using(db_alias).bulk_update(history_to_update, fields=['initiator', 'json_options'])
235+
190236

191237
def migrate_templates_data_backwards(apps, schema_editor):
192238
Template = apps.get_model('main', 'Template')
193239
PeriodicTask = apps.get_model('main', 'PeriodicTask')
240+
History = apps.get_model('main', 'History')
194241

195242
ExecutionTemplate = apps.get_model('main', 'ExecutionTemplate')
196243
ExecutionTemplateOption = apps.get_model('main', 'ExecutionTemplateOption')
@@ -216,8 +263,26 @@ def migrate_templates_data_backwards(apps, schema_editor):
216263
new_template_id=new_template.id,
217264
)
218265

219-
PeriodicTask.objects.using(db_alias).bulk_create([
220-
PeriodicTask(
266+
history_to_update = []
267+
268+
history_to_update_qs = History.objects \
269+
.using(db_alias) \
270+
.filter(initiator_type='template', initiator=new_template.id)
271+
for history in history_to_update_qs:
272+
history.initiator = old_template.id
273+
options = json.loads(history.json_options)
274+
template_option_id = options.get('template_option')
275+
if str(default_option.id) == template_option_id:
276+
del options['template_option']
277+
elif template_option_id is not None:
278+
option = other_options.filter(id=template_option_id).first()
279+
if option:
280+
options['template_option'] = option.name
281+
history.json_options = json.dumps(options)
282+
history_to_update.append(history)
283+
284+
for periodic_task in default_option.periodic_tasks.all():
285+
old_periodic_task = PeriodicTask.objects.create(
221286
name=periodic_task.name,
222287
notes=periodic_task.notes,
223288
mode='',
@@ -233,11 +298,21 @@ def migrate_templates_data_backwards(apps, schema_editor):
233298
project=new_template.project,
234299
template=old_template,
235300
)
236-
for periodic_task in default_option.periodic_tasks.all()
237-
])
238-
239-
PeriodicTask.objects.using(db_alias).bulk_create([
240-
PeriodicTask(
301+
history_to_update_qs = History.objects \
302+
.using(db_alias) \
303+
.filter(initiator_type='scheduler', initiator=periodic_task.id)
304+
for history in history_to_update_qs:
305+
history.initiator = old_periodic_task.id
306+
options = json.loads(history.json_options)
307+
if 'template' in options:
308+
del options['template']
309+
if 'template_option' in options:
310+
del options['template_option']
311+
history.json_options = json.dumps(options)
312+
history_to_update.append(history)
313+
314+
for periodic_task in TemplatePeriodicTask.objects.filter(template_option__in=other_options):
315+
old_periodic_task = PeriodicTask.objects.create(
241316
name=periodic_task.name,
242317
notes=periodic_task.notes,
243318
mode='',
@@ -253,9 +328,19 @@ def migrate_templates_data_backwards(apps, schema_editor):
253328
project=new_template.project,
254329
template=old_template,
255330
)
256-
for periodic_task in TemplatePeriodicTask.objects.filter(template_option__in=other_options)
257-
])
258-
331+
history_to_update_qs = History.objects \
332+
.using(db_alias) \
333+
.filter(initiator_type='scheduler', initiator=periodic_task.id)
334+
for history in history_to_update_qs:
335+
history.initiator = old_periodic_task.id
336+
options = json.loads(history.json_options)
337+
if 'template' in options:
338+
del options['template']
339+
options['template_option'] = old_periodic_task.template_opt
340+
history.json_options = json.dumps(options)
341+
history_to_update.append(history)
342+
343+
History.objects.using(db_alias).bulk_update(history_to_update, fields=['initiator', 'json_options'])
259344

260345
def migrate_history_data_direct(apps, schema_editor):
261346
History = apps.get_model('main', 'History')

polemarch/main/utils.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -348,16 +348,10 @@ def execute(self, plugin: str, project, execute_args, **kwargs):
348348
validate_inventory_arguments(plugin, execute_args, project)
349349

350350
task_class = project.task_handlers.backend('EXECUTION')
351-
plugin_class = self.backend(plugin)
352-
353-
mode = f'[{plugin} plugin]'
354-
if plugin_class.arg_shown_on_history_as_mode is not None:
355-
mode = execute_args.get(plugin_class.arg_shown_on_history_as_mode, mode)
356351

357352
history = self.create_history(
358353
project,
359354
plugin,
360-
mode,
361355
execute_args=execute_args,
362356
initiator=kwargs.pop('initiator', 0),
363357
initiator_type=kwargs.pop('initiator_type', 'project'),
@@ -383,27 +377,35 @@ def execute(self, plugin: str, project, execute_args, **kwargs):
383377

384378
return history
385379

386-
def create_history(self, project, kind, mode, execute_args, **kwargs):
380+
def create_history(self, project, plugin, execute_args, **kwargs):
387381
if not kwargs['save_result']:
388382
return None
389383

390-
history_execute_args = {**execute_args}
391-
inventory = history_execute_args.get('inventory', None)
392-
if isinstance(inventory, str):
393-
history_execute_args['inventory'] = inventory
394-
inventory = None
395-
elif isinstance(inventory, int):
396-
inventory = project.inventories.get(id=inventory)
384+
plugin_class = self.backend(plugin)
385+
386+
mode = f'[{plugin} plugin]'
387+
if plugin_class.arg_shown_on_history_as_mode is not None:
388+
mode = execute_args.get(plugin_class.arg_shown_on_history_as_mode, mode)
389+
390+
inventory = None
391+
if plugin_class.arg_shown_on_history_as_inventory is not None:
392+
inventory_field_name = plugin_class.arg_shown_on_history_as_inventory
393+
inventory = execute_args.get(inventory_field_name, None)
394+
if isinstance(inventory, str):
395+
execute_args['inventory'] = inventory
396+
inventory = None
397+
elif isinstance(inventory, int):
398+
inventory = project.inventories.get(id=inventory)
397399

398400
return project.history.create(
399401
status='DELAY',
400402
mode=mode,
401403
start_time=timezone.now(),
402404
inventory=inventory,
403405
project=project,
404-
kind=kind,
406+
kind=plugin,
405407
raw_stdout='',
406-
execute_args=history_execute_args,
408+
execute_args=execute_args,
407409
initiator=kwargs['initiator'],
408410
initiator_type=kwargs['initiator_type'],
409411
executor=kwargs['executor'],

polemarch/plugins/execution/ansible.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class BaseAnsiblePlugin(BasePlugin):
3232
-15: HistoryStatus.INTERRUPTED,
3333
}
3434

35+
arg_shown_on_history_as_inventory = 'inventory'
36+
3537
def __init__(self, options=None, output_handler=None):
3638
super().__init__(options, output_handler)
3739
self.inventory = None
@@ -160,7 +162,11 @@ class AnsiblePlaybook(BaseAnsiblePlugin):
160162
reference = ANSIBLE_REFERENCE.raw_dict['playbook']
161163
arg_shown_on_history_as_mode = 'playbook'
162164
serializer_fields = {
163-
'playbook': AutoCompletionField(autocomplete='AnsiblePlaybook', autocomplete_property='playbook')
165+
'playbook': AutoCompletionField(
166+
autocomplete='AnsiblePlaybook',
167+
autocomplete_property='playbook',
168+
autocomplete_represent='playbook',
169+
)
164170
}
165171

166172
@property

polemarch/plugins/execution/base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ class BasePlugin:
4343
``[<plugin name> plugin]`` string.
4444
"""
4545

46+
arg_shown_on_history_as_inventory: Optional[str] = None # pylint: disable=invalid-name
47+
"""
48+
Name of argument presented in generated serializer which will be shown on list history page as *Inventory*.
49+
"""
50+
4651
error_codes: Mapping[int, str] = {}
4752
"""
4853
This mapping will be looked up to choose an appropriate error message for history output if execution finished with

0 commit comments

Comments
 (0)