mirror of
https://github.com/ansible/awx.git
synced 2026-03-27 22:05:07 -02:30
Add WorkflowJob.instance_groups and distinguish from char_prompts
This removes a loop that ran on import the loop was giving the wrong behavior and it initialized too many fields as char_prompts fields With this, we will now enumerate the char_prompts type fields manually
This commit is contained in:
@@ -214,4 +214,24 @@ class Migration(migrations.Migration):
|
|||||||
to='main.InstanceGroup',
|
to='main.InstanceGroup',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WorkflowJobInstanceGroupMembership',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('position', models.PositiveIntegerField(db_index=True, default=None, null=True)),
|
||||||
|
('instancegroup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.instancegroup')),
|
||||||
|
('workflowjobnode', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.workflowjob')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='workflowjob',
|
||||||
|
name='instance_groups',
|
||||||
|
field=awx.main.fields.OrderedManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
editable=False,
|
||||||
|
related_name='workflow_job_instance_groups',
|
||||||
|
through='main.WorkflowJobInstanceGroupMembership',
|
||||||
|
to='main.InstanceGroup',
|
||||||
|
),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -489,3 +489,14 @@ class WorkflowJobNodeBaseInstanceGroupMembership(models.Model):
|
|||||||
default=None,
|
default=None,
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WorkflowJobInstanceGroupMembership(models.Model):
|
||||||
|
|
||||||
|
workflowjobnode = models.ForeignKey('WorkflowJob', on_delete=models.CASCADE)
|
||||||
|
instancegroup = models.ForeignKey('InstanceGroup', on_delete=models.CASCADE)
|
||||||
|
position = models.PositiveIntegerField(
|
||||||
|
null=True,
|
||||||
|
default=None,
|
||||||
|
db_index=True,
|
||||||
|
)
|
||||||
|
|||||||
@@ -943,6 +943,28 @@ class LaunchTimeConfigBase(BaseModel):
|
|||||||
# This is a solution to the nullable CharField problem, specific to prompting
|
# This is a solution to the nullable CharField problem, specific to prompting
|
||||||
char_prompts = JSONBlob(default=dict, blank=True)
|
char_prompts = JSONBlob(default=dict, blank=True)
|
||||||
|
|
||||||
|
# Define fields that are not really fields, but alias to char_prompts lookups
|
||||||
|
limit = NullablePromptPseudoField('limit')
|
||||||
|
scm_branch = NullablePromptPseudoField('scm_branch')
|
||||||
|
job_tags = NullablePromptPseudoField('job_tags')
|
||||||
|
skip_tags = NullablePromptPseudoField('skip_tags')
|
||||||
|
diff_mode = NullablePromptPseudoField('diff_mode')
|
||||||
|
job_type = NullablePromptPseudoField('job_type')
|
||||||
|
verbosity = NullablePromptPseudoField('verbosity')
|
||||||
|
forks = NullablePromptPseudoField('forks')
|
||||||
|
job_slice_count = NullablePromptPseudoField('job_slice_count')
|
||||||
|
timeout = NullablePromptPseudoField('timeout')
|
||||||
|
|
||||||
|
# NOTE: additional fields are assumed to exist but must be defined in subclasses
|
||||||
|
# due to technical limitations
|
||||||
|
SUBCLASS_FIELDS = (
|
||||||
|
'instance_groups', # needs a through model defined
|
||||||
|
'extra_vars', # alternates between extra_vars and extra_data
|
||||||
|
'credentials', # already a unified job and unified JT field
|
||||||
|
'labels', # already a unified job and unified JT field
|
||||||
|
'execution_environment', # already a unified job and unified JT field
|
||||||
|
)
|
||||||
|
|
||||||
def prompts_dict(self, display=False):
|
def prompts_dict(self, display=False):
|
||||||
data = {}
|
data = {}
|
||||||
# Some types may have different prompts, but always subset of JT prompts
|
# Some types may have different prompts, but always subset of JT prompts
|
||||||
@@ -977,15 +999,6 @@ class LaunchTimeConfigBase(BaseModel):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
for field_name in JobTemplate.get_ask_mapping().keys():
|
|
||||||
if field_name == 'extra_vars':
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
LaunchTimeConfigBase._meta.get_field(field_name)
|
|
||||||
except FieldDoesNotExist:
|
|
||||||
setattr(LaunchTimeConfigBase, field_name, NullablePromptPseudoField(field_name))
|
|
||||||
|
|
||||||
|
|
||||||
class LaunchTimeConfig(LaunchTimeConfigBase):
|
class LaunchTimeConfig(LaunchTimeConfigBase):
|
||||||
"""
|
"""
|
||||||
Common model for all objects that save details of a saved launch config
|
Common model for all objects that save details of a saved launch config
|
||||||
@@ -1004,12 +1017,9 @@ class LaunchTimeConfig(LaunchTimeConfigBase):
|
|||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# Credentials needed for non-unified job / unified JT models
|
# Fields needed for non-unified job / unified JT models, because they are defined on unified models
|
||||||
credentials = models.ManyToManyField('Credential', related_name='%(class)ss')
|
credentials = models.ManyToManyField('Credential', related_name='%(class)ss')
|
||||||
|
|
||||||
# Labels needed for non-unified job / unified JT models
|
|
||||||
labels = models.ManyToManyField('Label', related_name='%(class)s_labels')
|
labels = models.ManyToManyField('Label', related_name='%(class)s_labels')
|
||||||
|
|
||||||
execution_environment = models.ForeignKey(
|
execution_environment = models.ForeignKey(
|
||||||
'ExecutionEnvironment', null=True, blank=True, default=None, on_delete=polymorphic.SET_NULL, related_name='%(class)s_as_prompt'
|
'ExecutionEnvironment', null=True, blank=True, default=None, on_delete=polymorphic.SET_NULL, related_name='%(class)s_as_prompt'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -384,6 +384,10 @@ class WorkflowJobOptions(LaunchTimeConfigBase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
# Workflow jobs are used for sliced jobs, and thus, must be a conduit for any JT prompts
|
||||||
|
instance_groups = OrderedManyToManyField(
|
||||||
|
'InstanceGroup', related_name='workflow_job_instance_groups', blank=True, editable=False, through='WorkflowJobInstanceGroupMembership'
|
||||||
|
)
|
||||||
allow_simultaneous = models.BooleanField(default=False)
|
allow_simultaneous = models.BooleanField(default=False)
|
||||||
|
|
||||||
extra_vars_dict = VarsDictProperty('extra_vars', True)
|
extra_vars_dict = VarsDictProperty('extra_vars', True)
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx.main.models import JobTemplate, JobLaunchConfig, ExecutionEnvironment
|
from awx.main.models.jobs import JobTemplate, JobLaunchConfig, LaunchTimeConfigBase
|
||||||
|
from awx.main.models.execution_environments import ExecutionEnvironment
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -75,3 +76,28 @@ class TestConfigReversibility:
|
|||||||
print(prompts)
|
print(prompts)
|
||||||
print(config.prompts_dict())
|
print(config.prompts_dict())
|
||||||
assert config.prompts_dict() == prompts
|
assert config.prompts_dict() == prompts
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class TestLaunchConfigModels:
|
||||||
|
def get_concrete_subclasses(self, cls):
|
||||||
|
r = []
|
||||||
|
for c in cls.__subclasses__():
|
||||||
|
if c._meta.abstract:
|
||||||
|
r.extend(self.get_concrete_subclasses(c))
|
||||||
|
else:
|
||||||
|
r.append(c)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def test_non_job_config_complete(self):
|
||||||
|
"""This performs model validation which replaces code that used run on import."""
|
||||||
|
for field_name in JobTemplate.get_ask_mapping().keys():
|
||||||
|
if field_name in LaunchTimeConfigBase.SUBCLASS_FIELDS:
|
||||||
|
assert not hasattr(LaunchTimeConfigBase, field_name)
|
||||||
|
else:
|
||||||
|
assert hasattr(LaunchTimeConfigBase, field_name)
|
||||||
|
|
||||||
|
def test_subclass_fields_complete(self):
|
||||||
|
for cls in self.get_concrete_subclasses(LaunchTimeConfigBase):
|
||||||
|
for field_name in LaunchTimeConfigBase.SUBCLASS_FIELDS:
|
||||||
|
assert hasattr(cls, field_name)
|
||||||
|
|||||||
Reference in New Issue
Block a user