mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 04:10:44 -03:30
Merge branch 'master' into reintroduce-zeromq-unstable
This commit is contained in:
commit
f8cbdd65a5
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,7 +14,6 @@ awx/tower_warnings.log
|
||||
tower/tower_warnings.log
|
||||
celerybeat-schedule
|
||||
awx/ui/static/docs
|
||||
tools
|
||||
|
||||
# Python & setuptools
|
||||
__pycache__
|
||||
|
||||
1
Makefile
1
Makefile
@ -312,6 +312,7 @@ rpm-build/$(SDIST_TAR_FILE): dist/$(SDIST_TAR_FILE)
|
||||
mkdir -p rpm-build
|
||||
cp packaging/rpm/$(NAME).spec rpm-build/
|
||||
cp packaging/rpm/$(NAME).te rpm-build/
|
||||
cp packaging/rpm/$(NAME).sysconfig rpm-build/
|
||||
cp packaging/remove_tower_source.py rpm-build/
|
||||
if [ "$(OFFICIAL)" != "yes" ] ; then \
|
||||
(cd dist/ && tar zxf $(SDIST_TAR_FILE)) ; \
|
||||
|
||||
@ -277,12 +277,6 @@ class OrderByBackend(BaseFilterBackend):
|
||||
if field not in ('type', '-type'):
|
||||
new_order_by.append(field)
|
||||
queryset = queryset.order_by(*new_order_by)
|
||||
# Fetch the first result to run the query, otherwise we don't
|
||||
# always catch the FieldError for invalid field names.
|
||||
try:
|
||||
queryset[0]
|
||||
except IndexError:
|
||||
pass
|
||||
return queryset
|
||||
except FieldError, e:
|
||||
# Return a 400 for invalid field names.
|
||||
|
||||
@ -266,6 +266,13 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
summary_fields = SortedDict()
|
||||
for fk, related_fields in SUMMARIZABLE_FK_FIELDS.items():
|
||||
try:
|
||||
# A few special cases where we don't want to access the field
|
||||
# because it results in additional queries.
|
||||
if fk == 'job' and isinstance(obj, UnifiedJob):
|
||||
continue
|
||||
if fk == 'project' and isinstance(obj, InventorySource):
|
||||
continue
|
||||
|
||||
fkval = getattr(obj, fk, None)
|
||||
if fkval is None:
|
||||
continue
|
||||
@ -777,7 +784,7 @@ class HostSerializer(BaseSerializerWithVariables):
|
||||
else "",
|
||||
'status': j.job.status,
|
||||
'finished': j.job.finished,
|
||||
} for j in obj.job_host_summaries.filter(job__active=True).order_by('-created')[:5]]})
|
||||
} for j in obj.job_host_summaries.filter(job__active=True).select_related('job__job_template').order_by('-created')[:5]]})
|
||||
return d
|
||||
|
||||
def _get_host_port_from_name(self, name):
|
||||
@ -1452,9 +1459,7 @@ class ScheduleSerializer(BaseSerializer):
|
||||
unified_jobs = reverse('api:schedule_unified_jobs_list', args=(obj.pk,)),
|
||||
))
|
||||
if obj.unified_job_template and obj.unified_job_template.active:
|
||||
#TODO: Figure out why we have to do this
|
||||
ujt = UnifiedJobTemplate.objects.get(id=obj.unified_job_template.id)
|
||||
res['unified_job_template'] = ujt.get_absolute_url() #obj.unified_job_template.get_absolute_url()
|
||||
res['unified_job_template'] = obj.unified_job_template.get_absolute_url()
|
||||
return res
|
||||
|
||||
def validate_unified_job_template(self, attrs, source):
|
||||
|
||||
@ -15,6 +15,7 @@ import sys
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import FieldError
|
||||
from django.db.models import Q, Count, Sum
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.shortcuts import get_object_or_404
|
||||
@ -62,6 +63,8 @@ def api_exception_handler(exc):
|
||||
'''
|
||||
if isinstance(exc, IntegrityError):
|
||||
exc = ParseError(exc.args[0])
|
||||
if isinstance(exc, FieldError):
|
||||
exc = ParseError(exc.args[0])
|
||||
return exception_handler(exc)
|
||||
|
||||
|
||||
@ -1879,7 +1882,7 @@ class JobRelaunch(GenericAPIView):
|
||||
obj = self.get_object()
|
||||
data = {}
|
||||
data['passwords_needed_to_start'] = obj.passwords_needed_to_start
|
||||
data['ask_variables_on_launch'] = obj.ask_variables_on_launch
|
||||
#data['ask_variables_on_launch'] = obj.ask_variables_on_launch
|
||||
return Response(data)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
@ -223,7 +223,7 @@ class OrganizationAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by')
|
||||
qs = qs.select_related('created_by', 'modified_by')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
return qs.filter(Q(admins__in=[self.user]) | Q(users__in=[self.user]))
|
||||
@ -256,7 +256,7 @@ class InventoryAccess(BaseAccess):
|
||||
def get_queryset(self, allowed=None):
|
||||
allowed = allowed or PERMISSION_TYPES_ALLOWING_INVENTORY_READ
|
||||
qs = Inventory.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'organization')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'organization')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
qs = qs.filter(organization__active=True)
|
||||
@ -331,12 +331,12 @@ class HostAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'inventory',
|
||||
qs = qs.select_related('created_by', 'modified_by', 'inventory',
|
||||
'last_job__job_template',
|
||||
'last_job_host_summary')
|
||||
'last_job_host_summary__job')
|
||||
qs = qs.prefetch_related('groups')
|
||||
inventories_qs = self.user.get_queryset(Inventory)
|
||||
return qs.filter(inventory__in=inventories_qs)
|
||||
inventory_ids = set(self.user.get_queryset(Inventory).values_list('id', flat=True))
|
||||
return qs.filter(inventory_id__in=inventory_ids)
|
||||
|
||||
def can_read(self, obj):
|
||||
return obj and self.user.can_access(Inventory, 'read', obj.inventory)
|
||||
@ -404,10 +404,10 @@ class GroupAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'inventory')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'inventory')
|
||||
qs = qs.prefetch_related('parents', 'children', 'inventory_source')
|
||||
inventories_qs = self.user.get_queryset(Inventory)
|
||||
return qs.filter(inventory__in=inventories_qs)
|
||||
inventory_ids = set(self.user.get_queryset(Inventory).values_list('id', flat=True))
|
||||
return qs.filter(inventory_id__in=inventory_ids)
|
||||
|
||||
def can_read(self, obj):
|
||||
return obj and self.user.can_access(Inventory, 'read', obj.inventory)
|
||||
@ -464,10 +464,10 @@ class InventorySourceAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'group', 'inventory')
|
||||
inventories_qs = self.user.get_queryset(Inventory)
|
||||
return qs.filter(Q(inventory__in=inventories_qs) |
|
||||
Q(group__inventory__in=inventories_qs))
|
||||
qs = qs.select_related('created_by', 'modified_by', 'group', 'inventory')
|
||||
inventory_ids = set(self.user.get_queryset(Inventory).values_list('id', flat=True))
|
||||
return qs.filter(Q(inventory_id__in=inventory_ids) |
|
||||
Q(group__inventory_id__in=inventory_ids))
|
||||
|
||||
def can_read(self, obj):
|
||||
if obj and obj.group:
|
||||
@ -504,7 +504,7 @@ class InventoryUpdateAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = InventoryUpdate.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'inventory_source__group',
|
||||
qs = qs.select_related('created_by', 'modified_by', 'inventory_source__group',
|
||||
'inventory_source__inventory')
|
||||
inventory_sources_qs = self.user.get_queryset(InventorySource)
|
||||
return qs.filter(inventory_source__in=inventory_sources_qs)
|
||||
@ -531,16 +531,24 @@ class CredentialAccess(BaseAccess):
|
||||
model = Credential
|
||||
|
||||
def get_queryset(self):
|
||||
"""Return the queryset for credentials, based on what the user is
|
||||
permitted to see.
|
||||
"""
|
||||
# Create a base queryset.
|
||||
# If the user is a superuser, and therefore can see everything, this
|
||||
# is also sufficient, and we are done.
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'user', 'team')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'user', 'team')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
orgs_as_admin = self.user.admin_of_organizations.filter(active=True)
|
||||
|
||||
# Get the list of organizations for which the user is an admin
|
||||
orgs_as_admin_ids = set(self.user.admin_of_organizations.filter(active=True).values_list('id', flat=True))
|
||||
return qs.filter(
|
||||
Q(user=self.user) |
|
||||
Q(user__organizations__in=orgs_as_admin) |
|
||||
Q(user__admin_of_organizations__in=orgs_as_admin) |
|
||||
Q(team__organization__in=orgs_as_admin, team__active=True) |
|
||||
Q(user__organizations__id__in=orgs_as_admin_ids) |
|
||||
Q(user__admin_of_organizations__id__in=orgs_as_admin_ids) |
|
||||
Q(team__organization__id__in=orgs_as_admin_ids, team__active=True) |
|
||||
Q(team__users__in=[self.user], team__active=True)
|
||||
)
|
||||
|
||||
@ -598,7 +606,7 @@ class TeamAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'organization')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'organization')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
return qs.filter(
|
||||
@ -650,7 +658,7 @@ class ProjectAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Project.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'current_update', 'last_update')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'credential', 'current_update', 'last_update')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
allowed = [PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK]
|
||||
@ -696,9 +704,9 @@ class ProjectUpdateAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = ProjectUpdate.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'project')
|
||||
projects_qs = self.user.get_queryset(Project)
|
||||
return qs.filter(project__in=projects_qs)
|
||||
qs = qs.select_related('created_by', 'modified_by', 'project')
|
||||
project_ids = set(self.user.get_queryset(Project).values_list('id', flat=True))
|
||||
return qs.filter(project_id__in=project_ids)
|
||||
|
||||
def can_cancel(self, obj):
|
||||
return self.can_change(obj, {}) and obj.can_cancel
|
||||
@ -721,15 +729,15 @@ class PermissionAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'user', 'team', 'inventory',
|
||||
qs = qs.select_related('created_by', 'modified_by', 'user', 'team', 'inventory',
|
||||
'project')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
orgs_as_admin = self.user.admin_of_organizations.filter(active=True)
|
||||
orgs_as_admin_ids = set(self.user.admin_of_organizations.filter(active=True).values_list('id', flat=True))
|
||||
return qs.filter(
|
||||
Q(user__organizations__in=orgs_as_admin) |
|
||||
Q(user__admin_of_organizations__in=orgs_as_admin) |
|
||||
Q(team__organization__in=orgs_as_admin, team__active=True) |
|
||||
Q(user__organizations__in=orgs_as_admin_ids) |
|
||||
Q(user__admin_of_organizations__in=orgs_as_admin_ids) |
|
||||
Q(team__organization__in=orgs_as_admin_ids, team__active=True) |
|
||||
Q(user=self.user) |
|
||||
Q(team__users__in=[self.user], team__active=True)
|
||||
)
|
||||
@ -813,14 +821,14 @@ class JobTemplateAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'inventory', 'project',
|
||||
'credential')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'inventory', 'project',
|
||||
'credential', 'cloud_credential', 'next_schedule')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
credential_qs = self.user.get_queryset(Credential)
|
||||
credential_ids = set(self.user.get_queryset(Credential).values_list('id', flat=True))
|
||||
base_qs = qs.filter(
|
||||
Q(credential__in=credential_qs) | Q(credential__isnull=True),
|
||||
Q(cloud_credential__in=credential_qs) | Q(cloud_credential__isnull=True),
|
||||
Q(credential_id__in=credential_ids) | Q(credential__isnull=True),
|
||||
Q(cloud_credential_id__in=credential_ids) | Q(cloud_credential__isnull=True),
|
||||
)
|
||||
# FIXME: Check active status on related objects!
|
||||
org_admin_qs = base_qs.filter(
|
||||
@ -830,35 +838,30 @@ class JobTemplateAccess(BaseAccess):
|
||||
allowed_deploy = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY]
|
||||
allowed_check = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK]
|
||||
|
||||
# perm_qs = base_qs.filter(
|
||||
# Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]),
|
||||
# Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]),
|
||||
# inventory__permissions__permission_type__in=allowed,
|
||||
# project__permissions__permission_type__in=allowed,
|
||||
# inventory__permissions__active=True,
|
||||
# project__permissions__active=True,
|
||||
# inventory__permissions__pk=F('project__permissions__pk'),
|
||||
# )
|
||||
team_ids = set(Team.objects.filter(users__in=[self.user]).values_list('id', flat=True))
|
||||
|
||||
deploy_permissions_ids = set(Permission.objects.filter(
|
||||
Q(user=self.user) | Q(team_id__in=team_ids),
|
||||
active=True,
|
||||
permission_type__in=allowed_deploy,
|
||||
).values_list('id', flat=True))
|
||||
check_permissions_ids = set(Permission.objects.filter(
|
||||
Q(user=self.user) | Q(team_id__in=team_ids),
|
||||
active=True,
|
||||
permission_type__in=allowed_check,
|
||||
).values_list('id', flat=True))
|
||||
|
||||
perm_deploy_qs = base_qs.filter(
|
||||
Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]),
|
||||
Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]),
|
||||
job_type=PERM_INVENTORY_DEPLOY,
|
||||
inventory__permissions__permission_type__in=allowed_deploy,
|
||||
project__permissions__permission_type__in=allowed_deploy,
|
||||
inventory__permissions__active=True,
|
||||
project__permissions__active=True,
|
||||
inventory__permissions__in=deploy_permissions_ids,
|
||||
project__permissions__in=deploy_permissions_ids,
|
||||
inventory__permissions__pk=F('project__permissions__pk'),
|
||||
)
|
||||
|
||||
perm_check_qs = base_qs.filter(
|
||||
Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]),
|
||||
Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]),
|
||||
job_type=PERM_INVENTORY_CHECK,
|
||||
inventory__permissions__permission_type__in=allowed_check,
|
||||
project__permissions__permission_type__in=allowed_check,
|
||||
inventory__permissions__active=True,
|
||||
project__permissions__active=True,
|
||||
inventory__permissions__in=check_permissions_ids,
|
||||
project__permissions__in=check_permissions_ids,
|
||||
inventory__permissions__pk=F('project__permissions__pk'),
|
||||
)
|
||||
|
||||
@ -1010,13 +1013,14 @@ class JobAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'job_template', 'inventory',
|
||||
'project', 'credential')
|
||||
qs = qs.select_related('created_by', 'modified_by', 'job_template', 'inventory',
|
||||
'project', 'credential', 'cloud_credential', 'job_template')
|
||||
qs = qs.prefetch_related('unified_job_template')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
credential_qs = self.user.get_queryset(Credential)
|
||||
credential_ids = set(self.user.get_queryset(Credential).values_list('id', flat=True))
|
||||
base_qs = qs.filter(
|
||||
credential__in=credential_qs,
|
||||
credential_id__in=credential_ids,
|
||||
)
|
||||
org_admin_qs = base_qs.filter(
|
||||
project__organizations__admins__in=[self.user]
|
||||
@ -1036,28 +1040,33 @@ class JobAccess(BaseAccess):
|
||||
# inventory__permissions__pk=F('project__permissions__pk'),
|
||||
# )
|
||||
|
||||
team_ids = set(Team.objects.filter(users__in=[self.user]).values_list('id', flat=True))
|
||||
|
||||
deploy_permissions_ids = set(Permission.objects.filter(
|
||||
Q(user=self.user) | Q(team__in=team_ids),
|
||||
active=True,
|
||||
permission_type__in=allowed_deploy,
|
||||
).values_list('id', flat=True))
|
||||
check_permissions_ids = set(Permission.objects.filter(
|
||||
Q(user=self.user) | Q(team__in=team_ids),
|
||||
active=True,
|
||||
permission_type__in=allowed_check,
|
||||
).values_list('id', flat=True))
|
||||
|
||||
perm_deploy_qs = base_qs.filter(
|
||||
Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]),
|
||||
Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]),
|
||||
job_type=PERM_INVENTORY_DEPLOY,
|
||||
inventory__permissions__permission_type__in=allowed_deploy,
|
||||
project__permissions__permission_type__in=allowed_deploy,
|
||||
inventory__permissions__active=True,
|
||||
project__permissions__active=True,
|
||||
inventory__permissions__in=deploy_permissions_ids,
|
||||
project__permissions__in=deploy_permissions_ids,
|
||||
inventory__permissions__pk=F('project__permissions__pk'),
|
||||
)
|
||||
|
||||
perm_check_qs = base_qs.filter(
|
||||
Q(inventory__permissions__user=self.user) | Q(inventory__permissions__team__users__in=[self.user]),
|
||||
Q(project__permissions__user=self.user) | Q(project__permissions__team__users__in=[self.user]),
|
||||
job_type=PERM_INVENTORY_CHECK,
|
||||
inventory__permissions__permission_type__in=allowed_check,
|
||||
project__permissions__permission_type__in=allowed_check,
|
||||
inventory__permissions__active=True,
|
||||
project__permissions__active=True,
|
||||
inventory__permissions__in=check_permissions_ids,
|
||||
project__permissions__in=check_permissions_ids,
|
||||
inventory__permissions__pk=F('project__permissions__pk'),
|
||||
)
|
||||
|
||||
|
||||
# FIXME: I *think* this should work... needs more testing.
|
||||
return org_admin_qs | perm_deploy_qs | perm_check_qs
|
||||
|
||||
@ -1158,7 +1167,7 @@ class JobHostSummaryAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.distinct()
|
||||
qs = qs.select_related('created_by', 'job', 'job__job_template',
|
||||
qs = qs.select_related('created_by', 'modified_by', 'job', 'job__job_template',
|
||||
'host')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
@ -1184,7 +1193,7 @@ class JobEventAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.distinct()
|
||||
qs = qs.select_related('created_by', 'job', 'job__job_template',
|
||||
qs = qs.select_related('created_by', 'modified_by', 'job', 'job__job_template',
|
||||
'host', 'parent')
|
||||
qs = qs.prefetch_related('hosts', 'children')
|
||||
|
||||
@ -1228,7 +1237,17 @@ class UnifiedJobTemplateAccess(BaseAccess):
|
||||
qs = qs.filter(Q(Project___in=project_qs) |
|
||||
Q(InventorySource___in=inventory_source_qs) |
|
||||
Q(JobTemplate___in=job_template_qs))
|
||||
# FIXME: select/prefetch to optimize!
|
||||
qs = qs.select_related(
|
||||
'created_by',
|
||||
'modified_by',
|
||||
'project',
|
||||
'inventory',
|
||||
'credential',
|
||||
'cloud_credential',
|
||||
'next_schedule',
|
||||
'last_job',
|
||||
'current_job',
|
||||
)
|
||||
return qs
|
||||
|
||||
class UnifiedJobAccess(BaseAccess):
|
||||
@ -1249,7 +1268,21 @@ class UnifiedJobAccess(BaseAccess):
|
||||
Q(InventoryUpdate___in=inventory_update_qs) |
|
||||
Q(Job___in=job_qs) |
|
||||
Q(SystemJob___in=system_job_qs))
|
||||
# FIXME: select/prefetch to optimize!
|
||||
qs = qs.select_related(
|
||||
'created_by',
|
||||
'modified_by',
|
||||
'project',
|
||||
'inventory',
|
||||
'credential',
|
||||
'project___credential',
|
||||
'inventory_source___credential',
|
||||
'inventory_source___inventory',
|
||||
'job_template___inventory',
|
||||
'job_template___project',
|
||||
'job_template___credential',
|
||||
'job_template___cloud_credential',
|
||||
)
|
||||
qs = qs.prefetch_related('unified_job_template')
|
||||
return qs
|
||||
|
||||
class ScheduleAccess(BaseAccess):
|
||||
@ -1261,7 +1294,8 @@ class ScheduleAccess(BaseAccess):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('unified_job_template')
|
||||
qs = qs.select_related('created_by', 'modified_by')
|
||||
qs = qs.prefetch_related('unified_job_template')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
job_template_qs = self.user.get_queryset(JobTemplate)
|
||||
|
||||
@ -137,6 +137,13 @@ class UnifiedJobTemplate(PolymorphicModel, CommonModelNameNotUnique):
|
||||
editable=False,
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
real_instance = self.get_real_instance()
|
||||
if real_instance != self:
|
||||
return real_instance.get_absolute_url()
|
||||
else:
|
||||
return ''
|
||||
|
||||
def unique_error_message(self, model_class, unique_check):
|
||||
# If polymorphic_ctype is part of a unique check, return a list of the
|
||||
# remaining fields instead of the error message.
|
||||
@ -438,6 +445,13 @@ class UnifiedJob(PolymorphicModel, PasswordFieldsModel, CommonModelNameNotUnique
|
||||
editable=False,
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
real_instance = self.get_real_instance()
|
||||
if real_instance != self:
|
||||
return real_instance.get_absolute_url()
|
||||
else:
|
||||
return ''
|
||||
|
||||
@classmethod
|
||||
def _get_task_class(cls):
|
||||
raise NotImplementedError # Implement in subclasses.
|
||||
|
||||
@ -35,6 +35,7 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
list = PortalJobTemplateList,
|
||||
view= GenerateList,
|
||||
defaultUrl = GetBasePath('job_templates'),
|
||||
max_rows,
|
||||
buttons = {
|
||||
refresh: {
|
||||
mode: 'all',
|
||||
@ -79,6 +80,7 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
searchSize: 'col-lg-6 col-md-6'
|
||||
});
|
||||
|
||||
$scope.job_templatePageSize = $scope.getMaxRows();
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
@ -89,16 +91,10 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
PaginateInit({
|
||||
scope: $scope,
|
||||
list: list,
|
||||
url: defaultUrl
|
||||
url: defaultUrl,
|
||||
pageSize: $scope.job_templatePageSize
|
||||
});
|
||||
|
||||
// Called from Inventories tab, host failed events link:
|
||||
if ($routeParams.name) {
|
||||
$scope[list.iterator + 'SearchField'] = 'name';
|
||||
$scope[list.iterator + 'SearchValue'] = $routeParams.name;
|
||||
$scope[list.iterator + 'SearchFieldLabel'] = list.fields.name.label;
|
||||
}
|
||||
|
||||
$scope.search(list.iterator);
|
||||
|
||||
PortalJobsWidget({
|
||||
@ -126,22 +122,53 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
jobs_scope.search('portal_job'); //processEvent(event);
|
||||
});
|
||||
|
||||
$scope.getMaxRows = function(){
|
||||
var docw = $(window).width(),
|
||||
box_height, available_height, search_row, page_row, height, header, row_height;
|
||||
|
||||
available_height = Math.floor($(window).height() - $('#main-menu-container .navbar').outerHeight() - $('#refresh-row').outerHeight() - 35);
|
||||
$('.portal-job-template-container').height(available_height);
|
||||
$('.portal-container').height(available_height);
|
||||
search_row = Math.max($('.search-row:eq(0)').outerHeight(), 50);
|
||||
page_row = Math.max($('.page-row:eq(0)').outerHeight(), 33);
|
||||
header = 0; //Math.max($('#completed_jobs_table thead').height(), 41);
|
||||
height = Math.floor(available_height) - header - page_row - search_row ;
|
||||
if (docw < 765 && docw >= 493) {
|
||||
row_height = 27;
|
||||
}
|
||||
else if (docw < 493) {
|
||||
row_height = 47;
|
||||
}
|
||||
else if (docw < 865) {
|
||||
row_height = 87;
|
||||
}
|
||||
else if (docw < 925) {
|
||||
row_height = 67;
|
||||
}
|
||||
else if (docw < 1415) {
|
||||
row_height = 47;
|
||||
}
|
||||
else {
|
||||
row_height = 35;
|
||||
}
|
||||
max_rows = Math.floor(height / row_height);
|
||||
if (max_rows < 5){
|
||||
box_height = header+page_row + search_row + 40 + (5 * row_height);
|
||||
if (docw < 1140) {
|
||||
box_height += 40;
|
||||
}
|
||||
// $('.portal-job-template-container').height(box_height);
|
||||
max_rows = 5;
|
||||
}
|
||||
return max_rows;
|
||||
};
|
||||
|
||||
$scope.submitJob = function (id) {
|
||||
PlaybookRun({ scope: $scope, id: id });
|
||||
};
|
||||
|
||||
$scope.refresh = function () {
|
||||
$scope.$emit('LoadPortal');
|
||||
// Wait('start');
|
||||
// loadedCount = 0;
|
||||
// Rest.setUrl(GetBasePath('dashboard'));
|
||||
// Rest.get()
|
||||
// .success(function (data) {
|
||||
// $scope.$emit('dashboardReady', data);
|
||||
// })
|
||||
// .error(function (data, status) {
|
||||
// ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard: ' + status });
|
||||
// });
|
||||
};
|
||||
|
||||
$scope.refresh();
|
||||
|
||||
@ -75,7 +75,7 @@ angular.module('SourceFormDefinition', [])
|
||||
dataContainer: 'body'
|
||||
},
|
||||
group_by: {
|
||||
label: 'Group By',
|
||||
label: 'Only Group By',
|
||||
type: 'text',
|
||||
ngShow: "source && source.value == 'ec2'",
|
||||
addRequired: false,
|
||||
@ -83,40 +83,58 @@ angular.module('SourceFormDefinition', [])
|
||||
awMultiselect: 'group_by_choices',
|
||||
dataTitle: 'Group By',
|
||||
dataPlacement: 'right',
|
||||
awPopOver: "<p>FIXME: Create these automatic groups by default.</p>",
|
||||
awPopOver: "<p>FIXME: Create these automatic groups by default. give examples</p>",
|
||||
dataContainer: 'body'
|
||||
},
|
||||
group_tag_filters: {
|
||||
label: 'Tag Filters',
|
||||
type: 'text',
|
||||
ngShow: "source && source.value == 'ec2' && group_by.value.indexOf('tag_keys') >= 0", // FIXME: Not sure what's needed to make the last expression work.
|
||||
addRequired: false,
|
||||
editRequired: false,
|
||||
dataTitle: 'Tag Filters',
|
||||
dataPlacement: 'right',
|
||||
awPopOver: "<p>FIXME: When grouping by tags, specify which tag keys become groups.</p>",
|
||||
dataContainer: 'body'
|
||||
},
|
||||
custom_script: {
|
||||
// group_tag_filters: {
|
||||
// label: 'Tag Filters',
|
||||
// type: 'text',
|
||||
// ngShow: "source && source.value == 'ec2' && group_by.value.indexOf('tag_keys') >= 0", // FIXME: Not sure what's needed to make the last expression work.
|
||||
// addRequired: false,
|
||||
// editRequired: false,
|
||||
// dataTitle: 'Tag Filters',
|
||||
// dataPlacement: 'right',
|
||||
// awPopOver: "<p>FIXME: When grouping by tags, specify which tag keys become groups.</p>",
|
||||
// dataContainer: 'body'
|
||||
// },
|
||||
source_script: {
|
||||
label : "Custom Inventory Scripts",
|
||||
type: 'lookup',
|
||||
ngShow: "source && source.value !== '' && source.value === 'custom'",
|
||||
sourceModel: 'custom_script',
|
||||
sourceModel: 'source_script',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCustomScript()',
|
||||
ngClick: 'lookUpCustom_inventory()',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
},
|
||||
source_vars: {
|
||||
label: 'Source Variables',
|
||||
ngShow: "source && (source.value == 'file' || source.value == 'ec2' || source.value == 'custom')",
|
||||
extra_vars: {
|
||||
label: 'Environment Variables', //"{{vars_label}}" ,
|
||||
ngShow: "source && (source.value=='custom')",
|
||||
type: 'textarea',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
parseTypeName: 'envParseType',
|
||||
dataTitle: 'Source Variables',
|
||||
dataTitle: "Environment Variables", //'<p ng-show=source.value=="ec2">Source Variables<p>',
|
||||
dataPlacement: 'right',
|
||||
awPopOver: "<p>Provide key/value pairs using either YAML or JSON.</p>" +
|
||||
"JSON:<br />\n" +
|
||||
"<blockquote>{<br />\"somevar\": \"somevalue\",<br />\"password\": \"magic\"<br /> }</blockquote>\n" +
|
||||
"YAML:<br />\n" +
|
||||
"<blockquote>---<br />somevar: somevalue<br />password: magic<br /></blockquote>\n",
|
||||
dataContainer: 'body'
|
||||
},
|
||||
source_vars: {
|
||||
label: 'Source Variables', //"{{vars_label}}" ,
|
||||
ngShow: "source && (source.value == 'file' || source.value == 'ec2')",
|
||||
type: 'textarea',
|
||||
addRequired: false,
|
||||
editRequird: false,
|
||||
rows: 6,
|
||||
'default': '---',
|
||||
parseTypeName: 'envParseType',
|
||||
dataTitle: "Source Variables",
|
||||
dataPlacement: 'right',
|
||||
awPopOver: "<p>Override variables found in ec2.ini and used by the inventory update script. For a detailed description of these variables " +
|
||||
"<a href=\"https://github.com/ansible/ansible/blob/devel/plugins/inventory/ec2.ini\" target=\"_blank\">" +
|
||||
|
||||
@ -63,7 +63,7 @@ angular.module('CreateCustomInventoryHelper', [ 'Utilities', 'RestServices', 'Sc
|
||||
|
||||
SearchInit({
|
||||
scope: scope,
|
||||
set: 'custum_inventories',
|
||||
set: 'custom_inventories',
|
||||
list: list,
|
||||
url: defaultUrl
|
||||
});
|
||||
@ -187,12 +187,10 @@ function($compile, SchedulerInit, Rest, Wait, CustomInventoryList, CustomInvento
|
||||
view = GenerateList,
|
||||
list = CustomInventoryList,
|
||||
url = GetBasePath('inventory_scripts');
|
||||
// base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
|
||||
generator.inject(form, { id:'custom-script-dialog', mode: 'add' , scope:scope, related: false, breadCrumbs: false});
|
||||
generator.reset();
|
||||
|
||||
|
||||
// Save
|
||||
scope.formSave = function () {
|
||||
generator.clearApiErrors();
|
||||
@ -211,7 +209,7 @@ function($compile, SchedulerInit, Rest, Wait, CustomInventoryList, CustomInvento
|
||||
|
||||
SearchInit({
|
||||
scope: scope,
|
||||
set: 'custum_inventories',
|
||||
set: 'custom_inventories',
|
||||
list: list,
|
||||
url: url
|
||||
});
|
||||
@ -252,7 +250,6 @@ function($compile, CustomInventoryList, Rest, Wait, GenerateList, CustomInventor
|
||||
list = CustomInventoryList,
|
||||
master = {},
|
||||
url = GetBasePath('inventory_scripts');
|
||||
// base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
|
||||
generator.inject(form, {
|
||||
id:'custom-script-dialog',
|
||||
|
||||
@ -207,13 +207,13 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
}
|
||||
])
|
||||
|
||||
.factory('SourceChange', ['GetBasePath', 'CredentialList', 'LookUpInit', 'Empty', 'Wait', 'ParseTypeChange',
|
||||
function (GetBasePath, CredentialList, LookUpInit, Empty, Wait, ParseTypeChange) {
|
||||
.factory('SourceChange', ['GetBasePath', 'CredentialList', 'LookUpInit', 'Empty', 'Wait', 'ParseTypeChange', 'CustomInventoryList' ,
|
||||
function (GetBasePath, CredentialList, LookUpInit, Empty, Wait, ParseTypeChange, CustomInventoryList) {
|
||||
return function (params) {
|
||||
|
||||
var scope = params.scope,
|
||||
form = params.form,
|
||||
kind, url, callback;
|
||||
kind, url, callback, invUrl;
|
||||
|
||||
if (!Empty(scope.source)) {
|
||||
if (scope.source.value === 'file') {
|
||||
@ -234,7 +234,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
$('#source_form').removeClass('squeeze');
|
||||
} else if (scope.source.value === 'ec2') {
|
||||
scope.source_region_choices = scope.ec2_regions;
|
||||
//$('#s2id_group_source_regions').select2('data', []);
|
||||
$('#s2id_source_source_regions').select2('data', [{
|
||||
id: 'all',
|
||||
text: 'All'
|
||||
@ -273,6 +272,21 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
}
|
||||
if(scope.source.value==="custom"){
|
||||
invUrl = GetBasePath('inventory_scripts');
|
||||
LookUpInit({
|
||||
url: invUrl,
|
||||
scope: scope,
|
||||
form: form,
|
||||
// current_item: null,
|
||||
list: CustomInventoryList,
|
||||
field: 'source_script',
|
||||
input_type: 'radio'
|
||||
});
|
||||
scope.extra_vars = (Empty(scope.source_vars)) ? "---" : scope.source_vars;
|
||||
ParseTypeChange({ scope: scope, variable: 'extra_vars', parse_variable: form.fields.extra_vars.parseTypeName,
|
||||
field_id: 'source_extra_vars', onReady: callback });
|
||||
}
|
||||
if (scope.source.value === 'rax' || scope.source.value === 'ec2'|| scope.source.value==='gce' || scope.source.value === 'azure' || scope.source.value === 'vmware') {
|
||||
kind = (scope.source.value === 'rax') ? 'rax' : (scope.source.value==='gce') ? 'gce' : (scope.source.value==='azure') ? 'azure' : (scope.source.value === 'vmware') ? 'vmware' : 'aws' ;
|
||||
url = GetBasePath('credentials') + '?cloud=true&kind=' + kind;
|
||||
@ -850,6 +864,8 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
Wait('start');
|
||||
ParseTypeChange({ scope: sources_scope, variable: 'source_vars', parse_variable: SourceForm.fields.source_vars.parseTypeName,
|
||||
field_id: 'source_source_vars', onReady: waitStop });
|
||||
ParseTypeChange({ scope: sources_scope, variable: 'extra_vars', parse_variable: SourceForm.fields.extra_vars.parseTypeName,
|
||||
field_id: 'source_extra_vars', onReady: waitStop });
|
||||
}
|
||||
}
|
||||
else if ($(e.target).text() === 'Schedule') {
|
||||
@ -946,7 +962,12 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
// Parse source_vars, converting to YAML.
|
||||
sources_scope.source_vars = ParseVariableString(data.source_vars);
|
||||
master.source_vars = sources_scope.variables;
|
||||
} else if (data[fld] !== undefined) {
|
||||
}
|
||||
// else if(fld === "source_script"){
|
||||
// sources_scope[fld] = data
|
||||
// }
|
||||
|
||||
else if (data[fld] !== undefined) {
|
||||
sources_scope[fld] = data[fld];
|
||||
master[fld] = sources_scope[fld];
|
||||
}
|
||||
@ -1144,6 +1165,7 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
credential: sources_scope.credential,
|
||||
overwrite: sources_scope.overwrite,
|
||||
overwrite_vars: sources_scope.overwrite_vars,
|
||||
source_script: sources_scope.source_script,
|
||||
update_on_launch: sources_scope.update_on_launch,
|
||||
update_cache_timeout: (sources_scope.update_cache_timeout || 0)
|
||||
};
|
||||
@ -1156,11 +1178,19 @@ function($compile, SchedulerInit, Rest, Wait, SetSchedulesInnerDialogSize, Sched
|
||||
}
|
||||
data.source_regions = r.join();
|
||||
|
||||
if (sources_scope.source && (sources_scope.source.value === 'ec2' || sources_scope.source.value === 'custom')) {
|
||||
if (sources_scope.source && (sources_scope.source.value === 'ec2')) {
|
||||
// for ec2, validate variable data
|
||||
data.source_vars = ToJSON(sources_scope.envParseType, sources_scope.source_vars, true);
|
||||
}
|
||||
|
||||
if (sources_scope.source && (sources_scope.source.value === 'custom')) {
|
||||
data.source_vars = ToJSON(sources_scope.envParseType, sources_scope.extra_vars, true);
|
||||
}
|
||||
|
||||
if(sources_scope.source.value === 'custom'){
|
||||
delete(data.credential);
|
||||
}
|
||||
|
||||
if (!parseError) {
|
||||
Rest.setUrl(sources_scope.source_url);
|
||||
Rest.put(data)
|
||||
|
||||
@ -43,8 +43,10 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
delete(job_launch_data.extra_vars);
|
||||
if(!Empty(scope.credential)){
|
||||
job_launch_data.credential = scope.credential;
|
||||
}
|
||||
Rest.setUrl(url);
|
||||
Rest.post(job_launch_data)
|
||||
.success(function(data) {
|
||||
@ -386,6 +388,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
function buildHtml(extra_vars){
|
||||
|
||||
html += GenerateForm.buildHTML(JobVarsPromptForm, { mode: 'edit', modal: true, scope: scope });
|
||||
html = html.replace("</form>", "");
|
||||
scope.helpContainer = "<div style=\"display:inline-block; font-size: 12px; margin-top: 6px;\" class=\"help-container pull-right\">\n" +
|
||||
"<a href=\"\" id=\"awp-promote\" href=\"\" aw-pop-over=\"{{ helpText }}\" aw-tool-tip=\"Click for help\" aw-pop-over-watch=\"helpText\" " +
|
||||
"aw-tip-placement=\"top\" data-placement=\"bottom\" data-container=\"body\" data-title=\"Help\" class=\"help-link\"><i class=\"fa fa-question-circle\">" +
|
||||
@ -444,10 +447,9 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
question.index = index;
|
||||
|
||||
requiredAsterisk = (question.required===true) ? "prepend-asterisk" : "";
|
||||
|
||||
requiredClasses = (question.required===true) ? "ng-pristine ng-invalid-required ng-invalid" : "";
|
||||
|
||||
html+='<div id="taker_'+question.index+'" class="form-group '+requiredAsterisk+' ">';
|
||||
requiredClasses = (question.required===true) ? "ng-pristine ng-invalid-required ng-invalid" : "";
|
||||
html += '<label for="'+question.variable+'">'+question.question_name+'</label>\n';
|
||||
|
||||
if(!Empty(question.question_description)){
|
||||
@ -458,7 +460,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
if(question.type === 'text' ){
|
||||
html+='<input type="text" id="'+question.variable+'" ng-model="'+question.variable+'" '+
|
||||
'name="'+question.variable+'" '+
|
||||
'class="form-control ng-pristine ng-invalid-required ng-invalid" required="" >'+
|
||||
'class="form-control" ng-required='+question.required+'>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+ question.variable + '.$dirty && ' +
|
||||
'job_launch_form.'+question.variable+'.$error.required\">A value is required!</div>'+
|
||||
'<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>';
|
||||
@ -467,7 +469,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
if(question.type === "textarea"){
|
||||
scope[question.variable] = question.default || question.default_textarea;
|
||||
html+='<textarea id="'+question.variable+'" name="'+question.variable+'" ng-model="'+question.variable+'" '+
|
||||
'class="form-control ng-pristine ng-invalid-required ng-invalid final" required="" rows="3"></textarea>'+
|
||||
'class="form-control final" ng-required="'+question.required+'" rows="3"></textarea>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+ question.variable + '.$dirty && ' +
|
||||
'job_launch_form.'+question.variable+'.$error.required\">A value is required!</div>'+
|
||||
'<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>';
|
||||
@ -480,7 +482,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
html+='<div class="survey_taker_input" > ';
|
||||
for( j = 0; j<choices.length; j++){
|
||||
checked = (!Empty(question.default) && question.default.indexOf(choices[j])!==-1) ? "checked" : "";
|
||||
html+= '<input type="'+element+'" class="mc" ng-model="'+question.variable+'" ng-required="!'+question.variable+'" name="'+question.variable+ ' " id="'+question.variable+'" value=" '+choices[j]+' " '+checked+' >' +
|
||||
html+= '<input type="'+element+'" class="mc" ng-model="'+question.variable+'" ng-required="'+question.required+'" name="'+question.variable+ ' " id="'+question.variable+'" value=" '+choices[j]+' " '+checked+' >' +
|
||||
'<span>'+choices[j] +'</span><br>' ;
|
||||
}
|
||||
html+= '<div class="error survey_error" ng-show="job_launch_form.'+ question.variable + '.$dirty && ' +
|
||||
@ -515,18 +517,23 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
if(question.type === 'integer'){
|
||||
min = (!Empty(question.min)) ? Number(question.min) : "";
|
||||
max = (!Empty(question.max)) ? Number(question.max) : "" ;
|
||||
html+='<input type="number" id="'+question.variable+'" class=" form-control" name="'+question.variable+'" ng-min="'+min+'" ng-max="'+max+'" ng-model="'+question.variable+' " integer>'+
|
||||
html+='<input type="number" id="'+question.variable+'" ng-model="'+question.variable+'" class="form-control" name="'+question.variable+'" ng-min="'+min+'" ng-max="'+max+'" integer>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+ question.variable + '.$dirty && ' +
|
||||
'job_launch_form.'+question.variable+'.$error.required\">A value is required!</div>'+
|
||||
'<div class=\"error api-error\" ng-bind=\"" + fld + "_api_error\"></div>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$error.number || job_launch_form.'+question.variable+'.$error.integer">This is not valid integer!</div>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$error.ngMin || job_launch_form.'+question.variable+'.$error.ngMax"> The value must be in range {{'+min+'}} to {{'+max+'}}!</div>';
|
||||
|
||||
}
|
||||
|
||||
if(question.type === "float"){
|
||||
min = (!Empty(question.min)) ? question.min : "";
|
||||
max = (!Empty(question.max)) ? question.max : "" ;
|
||||
defaultValue = (!Empty(question.default)) ? question.default : (!Empty(question.default_float)) ? question.default_float : "" ;
|
||||
html+='<input type="number" id="'+question.variable+'" class=" form-control" name="'+question.variable+'" ng-min="'+min+'" ng-max="'+max+'" ng-model="'+question.variable+'" smart-float>'+
|
||||
html+='<input type="number" id="'+question.variable+'" ng-model="'+question.variable+'" class=" form-control" name="'+question.variable+'" ng-min="'+min+'" ng-max="'+max+'" smart-float>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$error.number || job_launch_form.'+question.variable+'.$error.float">This is not valid float!</div>'+
|
||||
'<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$error.ngMin || job_launch_form.'+question.variable+'.$error.ngMax"> The value must be in range {{'+min+'}} to {{'+max+'}}!</div>';
|
||||
// '<div class="error survey_error" ng-show="job_launch_form.'+question.variable+'.$dirty || job_launch_form.'+question.variable+'.$error.required"> A value is required!</div>';
|
||||
}
|
||||
html+='</div>';
|
||||
if(question.index === scope.survey_questions.length-1){
|
||||
@ -739,6 +746,12 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
if(passwords.length>0){
|
||||
scope.$emit('PromptForPasswords', passwords, html, url);
|
||||
}
|
||||
else if (scope.ask_variables_on_launch){
|
||||
scope.$emit('PromptForVars', html, url);
|
||||
}
|
||||
else if (!Empty(scope.survey_enabled) && scope.survey_enabled===true) {
|
||||
scope.$emit('PromptForSurvey', html, url);
|
||||
}
|
||||
else scope.$emit('StartPlaybookRun', url);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
@ -758,8 +771,8 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
launch_url = url;//data.related.start;
|
||||
scope.passwords_needed_to_start = data.passwords_needed_to_start;
|
||||
scope.prompt_for_vars = data.ask_variables_on_launch;
|
||||
// scope.extra_vars = data.variables_needed_to_start;
|
||||
scope.survey_enabled = data.survey_enabled;
|
||||
scope.ask_variables_on_launch = data.ask_variables_on_launch;
|
||||
|
||||
html = '<form class="ng-valid ng-valid-required" name="job_launch_form" id="job_launch_form" autocomplete="off" nonvalidate>';
|
||||
|
||||
|
||||
@ -138,7 +138,7 @@ angular.module('PaginationHelpers', ['Utilities', 'RefreshHelper', 'RefreshRelat
|
||||
connect = (/\/$/.test(new_url)) ? '?' : '&';
|
||||
new_url += connect + 'page=' + page;
|
||||
new_url += (scope[iterator + 'SearchParams']) ? '&' + scope[iterator + 'SearchParams'] +
|
||||
'&page_size=' + scope[iterator + '_page_size'] : 'page_size=' + scope[iterator + 'PageSize'];
|
||||
'&page_size=' + scope[iterator + '_page_size'] : '&page_size=' + scope[iterator + 'PageSize'];
|
||||
Wait('start');
|
||||
Refresh({ scope: scope, set: set, iterator: iterator, url: new_url });
|
||||
};
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
angular.module('CustomInventoryListDefinition', [])
|
||||
.value('CustomInventoryList', {
|
||||
|
||||
name: 'custum_inventories',
|
||||
name: 'custom_inventories',
|
||||
iterator: 'custom_inventory',
|
||||
selectTitle: 'Add custom inventory',
|
||||
editTitle: 'Custom Inventories',
|
||||
|
||||
@ -11,8 +11,8 @@
|
||||
'use strict';
|
||||
|
||||
angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
.factory('PortalJobsWidget', ['$rootScope', '$compile', 'LoadSchedulesScope', 'LoadJobsScope', 'PortalJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath',
|
||||
function ($rootScope, $compile, LoadSchedulesScope, LoadJobsScope, PortalJobsList, ScheduledJobsList, GetChoices, GetBasePath) {
|
||||
.factory('PortalJobsWidget', ['$rootScope', '$compile', 'LoadSchedulesScope', 'LoadJobsScope', 'PortalJobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath', 'PortalJobTemplateList',
|
||||
function ($rootScope, $compile, LoadSchedulesScope, LoadJobsScope, PortalJobsList, ScheduledJobsList, GetChoices, GetBasePath, PortalJobTemplateList) {
|
||||
return function (params) {
|
||||
var scope = params.scope,
|
||||
target = params.target,
|
||||
@ -70,6 +70,7 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
});
|
||||
|
||||
|
||||
|
||||
$(window).resize(_.debounce(function() {
|
||||
resizePortalJobsWidget();
|
||||
}, 500));
|
||||
@ -150,8 +151,9 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
setPortalJobsHeight();
|
||||
jobs_scope[PortalJobsList.iterator + '_page_size'] = max_rows;
|
||||
jobs_scope.changePageSize(PortalJobsList.name, PortalJobsList.iterator, false);
|
||||
// scheduled_scope[ScheduledJobsList.iterator + '_page_size'] = max_rows;
|
||||
// scheduled_scope.changePageSize(ScheduledJobsList.name, ScheduledJobsList.iterator, false);
|
||||
scope[PortalJobTemplateList.iterator + '_page_size'] = max_rows;
|
||||
scope[PortalJobTemplateList.iterator + 'PageSize'] = max_rows;
|
||||
scope.changePageSize(PortalJobTemplateList.name, PortalJobTemplateList.iterator, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<div id="configure-jobs" >
|
||||
|
||||
<div id="configure-jobs" ><div>
|
||||
<div class="tab-pane" id="configure-schedules-tab">
|
||||
<div id="configure-schedules-overlay"></div>
|
||||
<div id="configure-schedules-list"></div>
|
||||
|
||||
@ -205,7 +205,7 @@
|
||||
<a id="mobile_munin" target="_blank" ng-show="user_is_superuser" href="/munin" ng-hide="portalMode===true">Monitor Tower</a></li>
|
||||
<a href="#portal" id="mobile_portal_link" ng-hide="portalMode===true">Portal Mode</a></li>
|
||||
<a href="" id="mobile_view_license" ng-click="viewLicense()" ng-hide="portalMode===true">View License</a></li>
|
||||
<a href="" id="mobile_view_leave_portal" ng-click="leavePortal()" ng-show="portalMode===true">Exit Portal Mode</a></li>
|
||||
<a href="" id="mobile_view_leave_portal" ng-click="leavePortal()" ng-show="portalMode===true">Exit Portal</a></li>
|
||||
<a href="#/logout" id="mobile_logout">Logout</a>
|
||||
</nav>
|
||||
|
||||
@ -398,7 +398,37 @@
|
||||
<div id="license-modal-dialog" style="display: none;"></div>
|
||||
<div id="about-modal-dialog" style="display: none;" ng-include=" 'static/partials/cowsay-about.html ' "></div>
|
||||
<div id="custom-script-dialog" style="display:none;" > </div>
|
||||
<div id='configure-tower-dialog' style="display:none" ng-include = " ' static/partials/configure_tower.html' "></div>
|
||||
<div id='configure-tower-dialog' style="display:none" >
|
||||
<div id="configure-jobs" ></div>
|
||||
<div class="tab-pane" id="configure-schedules-tab">
|
||||
<div id="configure-schedules-overlay"></div>
|
||||
<div id="configure-schedules-list"></div>
|
||||
<div id="configure-schedules-form-container">
|
||||
<div id="configure-schedules-title">
|
||||
<h4 ng-bind="schedulesTitle"></h4>
|
||||
<button type="button" class="close pull-right" ng-click="cancelScheduleForm()">x</button>
|
||||
</div>
|
||||
<div id="configure-schedules-form-container-body">
|
||||
<div id="configure-schedules-form"></div>
|
||||
<div id="configure-schedules-detail"></div>
|
||||
</div>
|
||||
<div id="configure-schedules-buttons" >
|
||||
<a id="configure-schedules-flip-link" ng-show="formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-search-plus"></i> View Details</a>
|
||||
<a id="configure-schedules-flip-link" ng-show="!formShowing" ng-click="showScheduleDetail()" href=""><i class="fa fa-arrow-circle-left"></i> Back to options</a>
|
||||
<button type="button" class="btn btn-default btn-sm" id="configure-schedule-delete-button" ng-show="mode==='edit'" ng-click="deleteSystemSchedule($event)"><i class="fa fa-trash-o"></i> Delete</button>
|
||||
<button type="button" class="btn btn-default btn-sm" id="configure-reset-button" ng-click="cancelScheduleForm()"><i class="fa fa-times"></i> Cancel</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="configure-save-button" ng-click="saveScheduleForm()"><i class="fa fa-check"></i> Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="prompt-for-days" style="display:none">
|
||||
<form name="prompt_for_days_form" id="prompt_for_days_form">
|
||||
How many days of data would you like to <b>keep</b>? <br>
|
||||
<input type="number" min="1" id="days_to_keep" name="days_to_keep" value="30" ng-required="true" class="form-control ng-pristine ng-invalid-required ng-invalid" style="margin-top:10px;">
|
||||
<div class="error" ng-show="prompt_for_days_form.days_to_keep.$dirty && copy_form.new_copy_name.$error.required">A value is required!</div></input>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@ -16,15 +16,18 @@
|
||||
# Description: Ansible Tower provides an easy-to-use UI and dashboard, role-based access control and more for your Ansible initiative
|
||||
### END INIT INFO
|
||||
|
||||
if [ -e /etc/debian_version ]
|
||||
then
|
||||
SERVICES=(postgresql redis-server apache2 supervisor)
|
||||
# Default configured services
|
||||
if [ -e /etc/debian_version ]; then
|
||||
TOWER_CONFIG="/etc/default/ansible-tower"
|
||||
else
|
||||
SERVICES=(postgresql redis httpd supervisord)
|
||||
TOWER_CONFIG="/etc/sysconfig/ansible-tower"
|
||||
fi
|
||||
|
||||
# Load default configuration
|
||||
[ -e "${TOWER_CONFIG}" ] && . "${TOWER_CONFIG}"
|
||||
|
||||
service_action() {
|
||||
for svc in ${SERVICES[@]}; do
|
||||
for svc in ${TOWER_SERVICES}; do
|
||||
service ${svc} $1
|
||||
this_return=$?
|
||||
if [ $this_return -gt $worst_return ]; then
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user