rename to slicing and schema tweaks

This commit is contained in:
AlanCoding
2018-10-15 16:10:55 -04:00
parent 46d6dce738
commit bbd3edba47
26 changed files with 193 additions and 181 deletions

View File

@@ -221,17 +221,19 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
return group_children_map
@staticmethod
def parse_split_params(split_str):
m = re.match(r"split(?P<offset>\d+)of(?P<step>\d+)", split_str)
def parse_slice_params(slice_str):
m = re.match(r"slice(?P<number>\d+)of(?P<step>\d+)", slice_str)
if not m:
raise ParseError(_('Could not parse subset as split specification.'))
offset = int(m.group('offset'))
raise ParseError(_('Could not parse subset as slice specification.'))
number = int(m.group('number'))
step = int(m.group('step'))
if offset > step:
raise ParseError(_('Split offset must be greater than total number of splits.'))
return (offset, step)
if number > step:
raise ParseError(_('Slice number must be less than total number of slices.'))
elif number < 1:
raise ParseError(_('Slice number must be 1 or higher.'))
return (number, step)
def get_script_data(self, hostvars=False, towervars=False, show_all=False, subset=None):
def get_script_data(self, hostvars=False, towervars=False, show_all=False, slice_number=1, slice_count=1):
hosts_kw = dict()
if not show_all:
hosts_kw['enabled'] = True
@@ -239,14 +241,9 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
if towervars:
fetch_fields.append('enabled')
hosts = self.hosts.filter(**hosts_kw).order_by('name').only(*fetch_fields)
if subset:
if not isinstance(subset, six.string_types):
raise ParseError(_('Inventory subset argument must be a string.'))
if subset.startswith('split'):
offset, step = Inventory.parse_split_params(subset)
hosts = hosts[offset::step]
else:
raise ParseError(_('Subset does not use any supported syntax.'))
if slice_count > 1:
offset = slice_number - 1
hosts = hosts[offset::slice_count]
data = dict()
all_group = data.setdefault('all', dict())

View File

@@ -277,11 +277,11 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
default=False,
allows_field='credentials'
)
job_split_count = models.IntegerField(
job_slice_count = models.PositiveIntegerField(
blank=True,
default=0,
help_text=_("The number of jobs to split into at runtime. "
"Will cause the Job Template to launch a workflow if value is non-zero."),
default=1,
help_text=_("The number of jobs to slice into at runtime. "
"Will cause the Job Template to launch a workflow if value is greater than 1."),
)
admin_role = ImplicitRoleField(
@@ -302,7 +302,8 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
@classmethod
def _get_unified_job_field_names(cls):
return set(f.name for f in JobOptions._meta.fields) | set(
['name', 'description', 'schedule', 'survey_passwords', 'labels', 'credentials', 'internal_limit']
['name', 'description', 'schedule', 'survey_passwords', 'labels', 'credentials',
'job_slice_number', 'job_slice_count']
)
@property
@@ -328,13 +329,15 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
return self.create_unified_job(**kwargs)
def create_unified_job(self, **kwargs):
prevent_splitting = kwargs.pop('_prevent_splitting', False)
split_event = bool(self.job_split_count > 1 and (not prevent_splitting))
prevent_splitting = kwargs.pop('_prevent_slicing', False)
split_event = bool(self.job_slice_count > 1 and (not prevent_splitting))
if split_event:
# A Split Job Template will generate a WorkflowJob rather than a Job
from awx.main.models.workflow import WorkflowJobTemplate, WorkflowJobNode
kwargs['_unified_job_class'] = WorkflowJobTemplate._get_unified_job_class()
kwargs['_parent_field_name'] = "job_template"
kwargs.setdefault('_eager_fields', {})
kwargs['_eager_fields']['is_sliced_job'] = True
job = super(JobTemplate, self).create_unified_job(**kwargs)
if split_event:
try:
@@ -342,11 +345,11 @@ class JobTemplate(UnifiedJobTemplate, JobOptions, SurveyJobTemplateMixin, Resour
except JobLaunchConfig.DoesNotExist:
wj_config = JobLaunchConfig()
actual_inventory = wj_config.inventory if wj_config.inventory else self.inventory
for idx in xrange(min(self.job_split_count,
for idx in xrange(min(self.job_slice_count,
actual_inventory.hosts.count())):
create_kwargs = dict(workflow_job=job,
unified_job_template=self,
ancestor_artifacts=dict(job_split=idx))
ancestor_artifacts=dict(job_split=idx + 1))
WorkflowJobNode.objects.create(**create_kwargs)
return job
@@ -531,10 +534,17 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
on_delete=models.SET_NULL,
help_text=_('The SCM Refresh task used to make sure the playbooks were available for the job run'),
)
internal_limit = models.CharField(
max_length=1024,
default='',
editable=False,
job_slice_number = models.PositiveIntegerField(
blank=True,
default=0,
help_text=_("If part of a sliced job, the ID of the inventory slice operated on. "
"If not part of sliced job, parameter is not used."),
)
job_slice_count = models.PositiveIntegerField(
blank=True,
default=1,
help_text=_("If ran as part of sliced jobs, the total number of slices. "
"If 1, job is not part of a sliced job."),
)
@@ -580,10 +590,11 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
return JobEvent
def copy_unified_job(self, **new_prompts):
new_prompts['_prevent_splitting'] = True
if self.internal_limit:
new_prompts.setdefault('_eager_fields', {})
new_prompts['_eager_fields']['internal_limit'] = self.internal_limit # oddball, not from JT or prompts
# Needed for job slice relaunch consistency, do no re-spawn workflow job
# target same slice as original job
new_prompts['_prevent_slicing'] = True
new_prompts.setdefault('_eager_fields', {})
new_prompts['_eager_fields']['job_slice_number'] = self.job_slice_number
return super(Job, self).copy_unified_job(**new_prompts)
@property

View File

@@ -219,11 +219,13 @@ class WorkflowJobNode(WorkflowNodeBase):
data.update(accepted_fields)
# build ancestor artifacts, save them to node model for later
aa_dict = {}
is_root_node = True
for parent_node in self.get_parent_nodes():
is_root_node = False
aa_dict.update(parent_node.ancestor_artifacts)
if parent_node.job and hasattr(parent_node.job, 'artifacts'):
aa_dict.update(parent_node.job.artifacts)
if aa_dict:
if aa_dict and not is_root_node:
self.ancestor_artifacts = aa_dict
self.save(update_fields=['ancestor_artifacts'])
# process password list
@@ -252,18 +254,12 @@ class WorkflowJobNode(WorkflowNodeBase):
# ensure that unified jobs created by WorkflowJobs are marked
data['_eager_fields'] = {'launch_type': 'workflow'}
# Extra processing in the case that this is a split job
if 'job_split' in self.ancestor_artifacts:
if 'job_split' in self.ancestor_artifacts and is_root_node:
split_str = six.text_type(self.ancestor_artifacts['job_split'] + 1)
data['_eager_fields']['name'] = six.text_type("{} - {}").format(
self.unified_job_template.name[:512 - len(split_str) - len(' - ')],
split_str
)
data['_eager_fields']['allow_simultaneous'] = True
data['_eager_fields']['internal_limit'] = 'split{0}of{1}'.format(
self.ancestor_artifacts['job_split'],
self.workflow_job.workflow_job_nodes.count()
)
data['_prevent_splitting'] = True
data['_eager_fields']['job_slice_number'] = self.ancestor_artifacts['job_split']
data['_eager_fields']['job_slice_count'] = self.workflow_job.workflow_job_nodes.count()
data['_prevent_slicing'] = True
return data
@@ -459,11 +455,16 @@ class WorkflowJob(UnifiedJob, WorkflowJobOptions, SurveyJobMixin, JobNotificatio
)
job_template = models.ForeignKey(
'JobTemplate',
related_name='split_jobs',
related_name='slice_workflow_jobs',
blank=True,
null=True,
default=None,
on_delete=models.SET_NULL,
help_text=_("If automatically created for a sliced job run, the job template "
"the workflow job was created from."),
)
is_sliced_job = models.BooleanField(
default=False
)
@property