mirror of
https://github.com/ansible/awx.git
synced 2026-01-17 20:51:21 -03:30
Merge branch 'master' into expunge-zeromq-unstable
Conflicts: setup/roles/awx_install/handlers/main.yml
This commit is contained in:
commit
0e8121f7f1
@ -41,7 +41,7 @@ from awx.main.utils import update_scm_url, get_type_for_model, get_model_for_typ
|
||||
logger = logging.getLogger('awx.api.serializers')
|
||||
|
||||
# Fields that should be summarized regardless of object type.
|
||||
DEFAULT_SUMMARY_FIELDS = ('name', 'description')#, 'type')
|
||||
DEFAULT_SUMMARY_FIELDS = ('name', 'description')#, 'created_by', 'modified_by')#, 'type')
|
||||
|
||||
# Keys are fields (foreign keys) where, if found on an instance, summary info
|
||||
# should be added to the serialized data. Values are a tuple of field names on
|
||||
@ -49,7 +49,7 @@ DEFAULT_SUMMARY_FIELDS = ('name', 'description')#, 'type')
|
||||
# the related object).
|
||||
SUMMARIZABLE_FK_FIELDS = {
|
||||
'organization': DEFAULT_SUMMARY_FIELDS,
|
||||
'user': ('username', 'first_name', 'last_name'),
|
||||
'user': ('id', 'username', 'first_name', 'last_name'),
|
||||
'team': DEFAULT_SUMMARY_FIELDS,
|
||||
'inventory': DEFAULT_SUMMARY_FIELDS + ('has_active_failures',
|
||||
'total_hosts',
|
||||
@ -289,6 +289,15 @@ class BaseSerializer(serializers.ModelSerializer):
|
||||
# Can be raised by the reverse accessor for a OneToOneField.
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
if getattr(obj, 'created_by', None) and obj.created_by.is_active:
|
||||
summary_fields['created_by'] = SortedDict()
|
||||
for field in SUMMARIZABLE_FK_FIELDS['user']:
|
||||
summary_fields['created_by'][field] = getattr(obj.created_by, field)
|
||||
if getattr(obj, 'modified_by', None) and obj.modified_by.is_active:
|
||||
summary_fields['modified_by'] = SortedDict()
|
||||
for field in SUMMARIZABLE_FK_FIELDS['user']:
|
||||
summary_fields['modified_by'][field] = getattr(obj.modified_by, field)
|
||||
print summary_fields
|
||||
return summary_fields
|
||||
|
||||
def get_created(self, obj):
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
# Python
|
||||
import datetime
|
||||
import dateutil
|
||||
import functools
|
||||
import time
|
||||
import re
|
||||
import socket
|
||||
@ -431,30 +432,32 @@ class DashboardInventoryGraphView(APIView):
|
||||
return Response(dashboard_data)
|
||||
|
||||
|
||||
class UserCreateAPIMixin(object):
|
||||
"""A mixin subclass that ensures that only a superuser is able to create
|
||||
another superuser.
|
||||
def disallow_superuser_escalation(cls):
|
||||
"""Decorator that ensures that the post, put, and patch methods on the
|
||||
class, if they exist, perform a sanity check and disallow superuser
|
||||
escalation by non-superusers.
|
||||
"""
|
||||
def post(self, request, pk=None):
|
||||
self._superuser_sanity_check(request)
|
||||
return super(UserCreateAPIMixin, self).post(request, pk=pk)
|
||||
# Create a method decorator that ensures superuser escalation by
|
||||
# non-superusers is disallowed.
|
||||
def superuser_lockdown(method):
|
||||
@functools.wraps(method)
|
||||
def fx(self, request, *a, **kw):
|
||||
if not request.user.is_superuser:
|
||||
if request.DATA.get('is_superuser', False):
|
||||
raise PermissionDenied('Only superusers may create '
|
||||
'other superusers.')
|
||||
return method(self, request, *a, **kw)
|
||||
return fx
|
||||
|
||||
# def put(self, request, pk=None):
|
||||
# self._superuser_sanity_check(request)
|
||||
# return super(UserCreateAPIMixin, self).put(request, pk=pk)
|
||||
# Ensure that if post, put, or patch methods exist, that they are decorated
|
||||
# with the sanity check decorator.
|
||||
for vuln_method in ('post', 'put', 'patch'):
|
||||
original_method = getattr(cls, vuln_method, None)
|
||||
if original_method is not None:
|
||||
setattr(cls, vuln_method, superuser_lockdown(original_method))
|
||||
|
||||
# def patch(self, request, pk=None):
|
||||
# self._superuser_sanity_check(request)
|
||||
# return super(UserCreateAPIMixin, self).patch(request, pk=pk)
|
||||
|
||||
def _superuser_sanity_check(self, request):
|
||||
"""Ensure that if a non-superuser tries to create a superuser,
|
||||
that the request is rejected.
|
||||
"""
|
||||
if not request.user.is_superuser:
|
||||
if request.DATA.get('is_superuser', False):
|
||||
raise PermissionDenied('Only superusers may create '
|
||||
'other superusers.')
|
||||
# Return the class object.
|
||||
return cls
|
||||
|
||||
|
||||
class ScheduleList(ListAPIView):
|
||||
@ -518,14 +521,16 @@ class OrganizationInventoriesList(SubListAPIView):
|
||||
parent_model = Organization
|
||||
relationship = 'inventories'
|
||||
|
||||
class OrganizationUsersList(UserCreateAPIMixin, SubListCreateAPIView):
|
||||
@disallow_superuser_escalation
|
||||
class OrganizationUsersList(SubListCreateAPIView):
|
||||
|
||||
model = User
|
||||
serializer_class = UserSerializer
|
||||
parent_model = Organization
|
||||
relationship = 'users'
|
||||
|
||||
class OrganizationAdminsList(UserCreateAPIMixin, SubListCreateAPIView):
|
||||
@disallow_superuser_escalation
|
||||
class OrganizationAdminsList(SubListCreateAPIView):
|
||||
|
||||
model = User
|
||||
serializer_class = UserSerializer
|
||||
@ -565,7 +570,8 @@ class TeamDetail(RetrieveUpdateDestroyAPIView):
|
||||
model = Team
|
||||
serializer_class = TeamSerializer
|
||||
|
||||
class TeamUsersList(UserCreateAPIMixin, SubListCreateAPIView):
|
||||
@disallow_superuser_escalation
|
||||
class TeamUsersList(SubListCreateAPIView):
|
||||
|
||||
model = User
|
||||
serializer_class = UserSerializer
|
||||
@ -762,7 +768,9 @@ class ProjectUpdateCancel(GenericAPIView):
|
||||
else:
|
||||
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||
|
||||
class UserList(UserCreateAPIMixin, ListCreateAPIView):
|
||||
|
||||
@disallow_superuser_escalation
|
||||
class UserList(ListCreateAPIView):
|
||||
|
||||
model = User
|
||||
serializer_class = UserSerializer
|
||||
@ -841,6 +849,7 @@ class UserActivityStreamList(SubListAPIView):
|
||||
return qs.filter(Q(actor=parent) | Q(user__in=[parent]))
|
||||
|
||||
|
||||
|
||||
class UserDetail(RetrieveUpdateDestroyAPIView):
|
||||
|
||||
model = User
|
||||
@ -1467,6 +1476,7 @@ class JobTemplateLaunch(GenericAPIView):
|
||||
data['passwords_needed_to_start'] = obj.passwords_needed_to_start
|
||||
data['ask_variables_on_launch'] = obj.ask_variables_on_launch
|
||||
data['variables_needed_to_start'] = obj.variables_needed_to_start
|
||||
data['credential_needed_to_start'] = obj.credential is None
|
||||
data['survey_enabled'] = obj.survey_enabled
|
||||
return Response(data)
|
||||
|
||||
|
||||
@ -826,41 +826,56 @@ class JobTemplateAccess(BaseAccess):
|
||||
org_admin_qs = base_qs.filter(
|
||||
project__organizations__admins__in=[self.user]
|
||||
)
|
||||
allowed = [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY]
|
||||
perm_qs = base_qs.filter(
|
||||
allowed = [PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY]
|
||||
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'),
|
||||
# )
|
||||
|
||||
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]),
|
||||
inventory__permissions__permission_type__in=allowed,
|
||||
project__permissions__permission_type__in=allowed,
|
||||
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__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__pk=F('project__permissions__pk'),
|
||||
)
|
||||
|
||||
# FIXME: I *think* this should work... needs more testing.
|
||||
return org_admin_qs | perm_qs
|
||||
return org_admin_qs | perm_deploy_qs | perm_check_qs
|
||||
|
||||
def can_read(self, obj):
|
||||
# you can only see the job templates that you have permission to launch.
|
||||
data = {
|
||||
'job_type': obj.job_type,
|
||||
}
|
||||
if obj.inventory and obj.inventory.pk:
|
||||
data['inventory'] = obj.inventory.pk
|
||||
if obj.project and obj.project.pk:
|
||||
data['project'] = obj.project.pk
|
||||
if obj.credential:
|
||||
data['credential'] = obj.credential.pk
|
||||
if obj.cloud_credential:
|
||||
data['cloud_credential'] = obj.cloud_credential.pk
|
||||
return self.can_add(data)
|
||||
return self.can_start(obj)
|
||||
|
||||
def can_add(self, data):
|
||||
'''
|
||||
a user can create a job template if they are a superuser, an org admin
|
||||
of any org that the project is a member, or if they have user or team
|
||||
based permissions tying the project to the inventory source for the
|
||||
given action. users who are able to create deploy jobs can also make
|
||||
check (dry run) jobs.
|
||||
given action as well as the 'create' deploy permission.
|
||||
Users who are able to create deploy jobs can also run normal and check (dry run) jobs.
|
||||
'''
|
||||
if not data or '_method' in data: # So the browseable API will work?
|
||||
return True
|
||||
@ -950,29 +965,32 @@ class JobTemplateAccess(BaseAccess):
|
||||
if obj.inventory is None or obj.project is None:
|
||||
return False
|
||||
# If the user has admin access to the project they can start a job
|
||||
if self.user.can_access(Project, 'admin', obj.project):
|
||||
if self.user.can_access(Project, 'admin', obj.project, None):
|
||||
return True
|
||||
|
||||
# Otherwise check for explicitly granted permissions
|
||||
permission_qs = Permission.objects.filter(
|
||||
Q(user=self.user) | Q(team__users__in=[self.user]),
|
||||
inventory=inventory,
|
||||
project=project,
|
||||
inventory=obj.inventory,
|
||||
project=obj.project,
|
||||
permission_type__in=[PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY],
|
||||
)
|
||||
|
||||
has_perm = False
|
||||
for perm in permission_qs:
|
||||
# If you have job template create permission that implies both CHECK and DEPLOY
|
||||
# If you have DEPLOY permissions you can run both CHECK and DEPLOY
|
||||
if perm.permission_type in [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY]:
|
||||
if perm.permission_type in [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY] and \
|
||||
obj.job_type == PERM_INVENTORY_DEPLOY:
|
||||
has_perm = True
|
||||
# If you only have CHECK permission then you can only run CHECK
|
||||
if perm.permission_type == PERM_INVENTORY_CHECK and perm.permission_type == PERM_INVENTORY_CHECK:
|
||||
if perm.permission_type in [PERM_JOBTEMPLATE_CREATE, PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK] and \
|
||||
obj.job_type == PERM_INVENTORY_CHECK:
|
||||
has_perm = True
|
||||
|
||||
dep_access = self.user.can_access(Inventory, 'read', obj.inventory) and \
|
||||
self.user.can_access(Project, 'read', obj.project)
|
||||
return self.can_read(obj) and dep_access and has_perm
|
||||
return dep_access and has_perm
|
||||
|
||||
def can_change(self, obj, data):
|
||||
return self.can_read(obj) and self.can_add(data)
|
||||
@ -998,17 +1016,44 @@ class JobAccess(BaseAccess):
|
||||
project__organizations__admins__in=[self.user]
|
||||
)
|
||||
allowed = [PERM_INVENTORY_CHECK, PERM_INVENTORY_DEPLOY]
|
||||
perm_qs = base_qs.filter(
|
||||
|
||||
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'),
|
||||
# )
|
||||
|
||||
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]),
|
||||
inventory__permissions__permission_type__in=allowed,
|
||||
project__permissions__permission_type__in=allowed,
|
||||
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__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__pk=F('project__permissions__pk'),
|
||||
)
|
||||
|
||||
# FIXME: I *think* this should work... needs more testing.
|
||||
return org_admin_qs | perm_qs
|
||||
return org_admin_qs | perm_deploy_qs | perm_check_qs
|
||||
|
||||
def can_add(self, data):
|
||||
if not data or '_method' in data: # So the browseable API will work?
|
||||
|
||||
@ -339,12 +339,13 @@ class BaseTask(Task):
|
||||
- /etc/tower (to prevent obtaining db info or secret key)
|
||||
- /var/lib/awx (except for current project)
|
||||
- /var/log/tower
|
||||
- /var/log/supervisor
|
||||
- /tmp (except for own tmp files)
|
||||
'''
|
||||
new_args = [getattr(settings, 'AWX_PROOT_CMD', 'proot'), '-r', '/']
|
||||
hide_paths = ['/etc/tower', '/var/lib/awx', '/var/log/tower',
|
||||
tempfile.gettempdir(), settings.PROJECTS_ROOT,
|
||||
settings.JOBOUTPUT_ROOT]
|
||||
'/var/log/supervisor', tempfile.gettempdir(),
|
||||
settings.PROJECTS_ROOT, settings.JOBOUTPUT_ROOT]
|
||||
hide_paths.extend(getattr(settings, 'AWX_PROOT_HIDE_PATHS', None) or [])
|
||||
for path in sorted(set(hide_paths)):
|
||||
if not os.path.exists(path):
|
||||
@ -1052,7 +1053,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
pass
|
||||
elif inventory_update.source == 'custom':
|
||||
for env_k in inventory_update.source_vars_dict:
|
||||
if str(env_k) not in os.environ:
|
||||
if str(env_k) not in os.environ and str(env_k) not in settings.INV_ENV_VARIABLE_BLACKLIST:
|
||||
env[str(env_k)] = unicode(inventory_update.source_vars_dict[env_k])
|
||||
return env
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
# Python
|
||||
from distutils.version import StrictVersion as Version
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
@ -176,6 +177,15 @@ TEST_PROOT_PLAYBOOK = '''
|
||||
assert:
|
||||
that:
|
||||
- "not temp_stat.stat.exists"
|
||||
- name: check for supervisor log path
|
||||
stat: path={{ supervisor_log_path }}
|
||||
register: supervisor_log_stat
|
||||
when: supervisor_log_path is defined
|
||||
- name: check that supervisor log path was not found
|
||||
assert:
|
||||
that:
|
||||
- "not supervisor_log_stat.stat.exists"
|
||||
when: supervisor_log_path is defined
|
||||
- name: try to run a tower-manage command
|
||||
command: tower-manage validate
|
||||
ignore_errors: true
|
||||
@ -1353,6 +1363,11 @@ class RunJobTest(BaseCeleryTest):
|
||||
# Create a temp directory that should not be visible to the playbook.
|
||||
temp_path = tempfile.mkdtemp()
|
||||
self._temp_paths.append(temp_path)
|
||||
# Find a file in supervisor logs that should not be visible.
|
||||
try:
|
||||
supervisor_log_path = glob.glob('/var/log/supervisor/*')[0]
|
||||
except IndexError:
|
||||
supervisor_log_path = None
|
||||
# Create our test project and job template.
|
||||
self.create_test_project(TEST_PROOT_PLAYBOOK)
|
||||
project_path = self.project.local_path
|
||||
@ -1364,6 +1379,8 @@ class RunJobTest(BaseCeleryTest):
|
||||
'other_project_path': other_project_path,
|
||||
'temp_path': temp_path,
|
||||
}
|
||||
if supervisor_log_path:
|
||||
extra_vars['supervisor_log_path'] = supervisor_log_path
|
||||
job = self.create_test_job(job_template=job_template, verbosity=3,
|
||||
extra_vars=json.dumps(extra_vars))
|
||||
self.assertEqual(job.status, 'new')
|
||||
|
||||
@ -193,10 +193,13 @@ class VMwareInventory(object):
|
||||
host_info = {
|
||||
'name': host.name,
|
||||
'tag': host.tag,
|
||||
'datastores': self._get_obj_info(host.datastore, depth=0),
|
||||
'networks': self._get_obj_info(host.network, depth=0),
|
||||
'vms': self._get_obj_info(host.vm, depth=0),
|
||||
}
|
||||
for attr in ('datastore', 'network', 'vm'):
|
||||
try:
|
||||
value = getattr(host, attr)
|
||||
host_info['%ss' % attr] = self._get_obj_info(value, depth=0)
|
||||
except AttributeError:
|
||||
host_info['%ss' % attr] = []
|
||||
for k, v in self._get_obj_info(host.summary, depth=0).items():
|
||||
if isinstance(v, collections.MutableMapping):
|
||||
for k2, v2 in v.items():
|
||||
@ -219,11 +222,21 @@ class VMwareInventory(object):
|
||||
vm_info = {
|
||||
'name': vm.name,
|
||||
'tag': vm.tag,
|
||||
'datastores': self._get_obj_info(vm.datastore, depth=0),
|
||||
'networks': self._get_obj_info(vm.network, depth=0),
|
||||
'resourcePool': self._get_obj_info(vm.resourcePool, depth=0),
|
||||
'guestState': vm.guest.guestState,
|
||||
}
|
||||
for attr in ('datastore', 'network'):
|
||||
try:
|
||||
value = getattr(vm, attr)
|
||||
vm_info['%ss' % attr] = self._get_obj_info(value, depth=0)
|
||||
except AttributeError:
|
||||
vm_info['%ss' % attr] = []
|
||||
try:
|
||||
vm_info['resourcePool'] = self._get_obj_info(vm.resourcePool, depth=0)
|
||||
except AttributeError:
|
||||
vm_info['resourcePool'] = ''
|
||||
try:
|
||||
vm_info['guestState'] = vm.guest.guestState
|
||||
except AttributeError:
|
||||
vm_info['guestState'] = ''
|
||||
for k, v in self._get_obj_info(vm.summary, depth=0).items():
|
||||
if isinstance(v, collections.MutableMapping):
|
||||
for k2, v2 in v.items():
|
||||
|
||||
@ -351,6 +351,8 @@ RAX_GROUP_FILTER = r'^(?!instance-.+).+$'
|
||||
RAX_HOST_FILTER = r'^.+$'
|
||||
RAX_EXCLUDE_EMPTY_GROUPS = True
|
||||
|
||||
INV_ENV_VARIABLE_BLACKLIST = ("HOME", "_")
|
||||
|
||||
# ----------------
|
||||
# -- Amazon EC2 --
|
||||
# ----------------
|
||||
|
||||
@ -649,6 +649,10 @@ angular.module('Tower', [
|
||||
$AnsibleConfig = Store('AnsibleConfig');
|
||||
}
|
||||
|
||||
//the authorization controller redirects to the home page automatcially if there is no last path defined. in order to override
|
||||
// this, set the last path to /portal for instances where portal is visited for the first time.
|
||||
$rootScope.lastPath = ($location.path() === "/portal") ? 'portal' : undefined;
|
||||
|
||||
LoadConfig();
|
||||
}
|
||||
]);
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips
|
||||
|
||||
debug_mode: true, // Enable console logging messages
|
||||
debug_mode: false, // Enable console logging messages
|
||||
|
||||
password_strength: 45, // User password strength. Integer between 0 and 100, 100 being impossibly strong.
|
||||
// This value controls progress bar colors:
|
||||
|
||||
@ -77,10 +77,9 @@ function JobsListController ($rootScope, $log, $scope, $compile, $routeParams, C
|
||||
case 'pending':
|
||||
case 'waiting':
|
||||
queued_scope.search('queued_job');
|
||||
break;
|
||||
case 'successful':
|
||||
completed_scope.search('completed_job');
|
||||
break;
|
||||
case 'successful':
|
||||
case 'failed':
|
||||
case 'error':
|
||||
case 'canceled':
|
||||
|
||||
@ -79,7 +79,6 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
searchSize: 'col-lg-6 col-md-6'
|
||||
});
|
||||
|
||||
$rootScope.flashMessage = null;
|
||||
|
||||
SearchInit({
|
||||
scope: $scope,
|
||||
@ -120,49 +119,11 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
$('.list-well:eq(1)').css('margin-top' , '0px');
|
||||
});
|
||||
|
||||
// function processEvent(event) {
|
||||
// switch(event.status) {
|
||||
// case 'running':
|
||||
// jobs_scope.search('running_job');
|
||||
// jobs_scope.search('queued_job');
|
||||
|
||||
// break;
|
||||
// case 'new':
|
||||
// case 'pending':
|
||||
// case 'waiting':
|
||||
// jobs_scope.search('queued_job');
|
||||
|
||||
// break;
|
||||
// case 'successful':
|
||||
// jobs_scope.search('completed_job');
|
||||
// case 'failed':
|
||||
// case 'error':
|
||||
// case 'canceled':
|
||||
// jobs_scope.search('completed_job');
|
||||
// jobs_scope.search('running_job');
|
||||
// jobs_scope.search('queued_job');
|
||||
// }
|
||||
// }
|
||||
|
||||
if ($rootScope.removeJobStatusChange) {
|
||||
$rootScope.removeJobStatusChange();
|
||||
}
|
||||
$rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange', function() {
|
||||
jobs_scope.refreshJobs();
|
||||
// if(data.status==='pending'){
|
||||
// // $scope.refresh();
|
||||
// $('#portal-jobs').empty();
|
||||
// // $rootScope.flashMessage = null;
|
||||
// PortalJobsWidget({
|
||||
// scope: $scope,
|
||||
// target: 'portal-jobs',
|
||||
// searchSize: 'col-lg-6 col-md-6'
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
//x`processEvent(data);
|
||||
|
||||
jobs_scope.search('portal_job'); //processEvent(event);
|
||||
});
|
||||
|
||||
$scope.submitJob = function (id) {
|
||||
|
||||
@ -53,7 +53,6 @@ angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'Credential
|
||||
$('#password-modal').dialog('close');
|
||||
}
|
||||
scope.$emit(callback, data);
|
||||
scope.$destroy();
|
||||
})
|
||||
.error(function(data, status) {
|
||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
||||
@ -241,7 +240,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
html += "<label for=\"" + fld + "\">" + field.label + "</label>\n";
|
||||
html += "<input type=\"password\" ";
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += "ng-keydown=\"keydown($event)\" ";
|
||||
// html += "ng-keydown=\"keydown($event)\" ";
|
||||
html += 'name="' + fld + '" ';
|
||||
html += "class=\"password-field form-control input-sm\" ";
|
||||
html += (field.associated) ? "ng-change=\"clearPWConfirm('" + field.associated + "')\" " : "";
|
||||
@ -262,7 +261,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
html += "<label for=\"" + fld + "\"> " + field.label + "</label>\n";
|
||||
html += "<input type=\"password\" ";
|
||||
html += "ng-model=\"" + fld + '" ';
|
||||
html += "ng-keydown=\"keydown($event)\" ";
|
||||
// html += "ng-keydown=\"keydown($event)\" ";
|
||||
html += 'name="' + fld + '" ';
|
||||
html += "class=\"form-control input-sm\" ";
|
||||
html += "ng-change=\"checkStatus()\" ";
|
||||
@ -323,11 +322,11 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
// $('#password-modal').dialog('open');
|
||||
// $('#password-accept-button').attr({ "disabled": "disabled" });
|
||||
// });
|
||||
scope.keydown = function(e){
|
||||
if(e.keyCode===13){
|
||||
scope.passwordAccept();
|
||||
}
|
||||
};
|
||||
// scope.keydown = function(e){
|
||||
// if(e.keyCode===13){
|
||||
// scope.passwordAccept();
|
||||
// }
|
||||
// };
|
||||
|
||||
// scope.passwordAccept = function() {
|
||||
// if (!scope.password_form.$invalid) {
|
||||
@ -764,7 +763,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
}
|
||||
scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function(e, data) {
|
||||
//var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if(scope.portalMode===false || scope.$parent.portalMode===false){
|
||||
if(scope.portalMode===false || scope.$parent.portalMode===false ){
|
||||
$location.path('/jobs/' + data.job);
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +87,9 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job
|
||||
else if (scope.jobs) {
|
||||
list = scope.jobs;
|
||||
}
|
||||
else if(scope.portal_jobs){
|
||||
list=scope.portal_jobs;
|
||||
}
|
||||
job = Find({ list: list, key: 'id', val: id });
|
||||
if (job.type === 'job') {
|
||||
if(scope.$parent.portalMode===true){
|
||||
@ -405,6 +408,9 @@ angular.module('JobsHelper', ['Utilities', 'RestServices', 'FormGenerator', 'Job
|
||||
JobsControllerInit({ scope: scope, parent_scope: parent_scope });
|
||||
JobsListUpdate({ scope: scope, parent_scope: parent_scope, list: list });
|
||||
parent_scope.$emit('listLoaded');
|
||||
// setTimeout(function(){
|
||||
// scope.$apply();
|
||||
// }, 300);
|
||||
});
|
||||
|
||||
if (base === 'jobs' && list.name === 'completed_jobs') {
|
||||
|
||||
@ -14,8 +14,8 @@
|
||||
angular.module('PortalJobsListDefinition', [])
|
||||
.value( 'PortalJobsList', {
|
||||
|
||||
name: 'jobs',
|
||||
iterator: 'job',
|
||||
name: 'portal_jobs',
|
||||
iterator: 'portal_job',
|
||||
editTitle: 'Jobs',
|
||||
'class': 'table-condensed',
|
||||
index: false,
|
||||
@ -39,8 +39,8 @@ angular.module('PortalJobsListDefinition', [])
|
||||
columnClass: 'col-lg-1 col-md-2 col-sm-2 col-xs-2',
|
||||
// awToolTip: "{{ job.status_tip }}",
|
||||
// awTipPlacement: "top",
|
||||
dataTitle: "{{ job.status_popover_title }}",
|
||||
icon: 'icon-job-{{ job.status }}',
|
||||
dataTitle: "{{ portal_job.status_popover_title }}",
|
||||
icon: 'icon-job-{{ portal_job.status }}',
|
||||
iconOnly: true,
|
||||
// ngClick:"viewJobLog(job.id)",
|
||||
searchable: true,
|
||||
@ -73,7 +73,7 @@ angular.module('PortalJobsListDefinition', [])
|
||||
fieldActions: {
|
||||
job_details: {
|
||||
mode: 'all',
|
||||
ngClick: "viewJobLog(job.id)",
|
||||
ngClick: "viewJobLog(portal_job.id)",
|
||||
awToolTip: 'View job details',
|
||||
dataPlacement: 'top'
|
||||
}
|
||||
|
||||
@ -19,23 +19,12 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
choicesCount = 0,
|
||||
listCount = 0,
|
||||
jobs_scope = scope.$new(true),
|
||||
// completed_scope = scope.$new(true),
|
||||
// running_scope = scope.$new(true),
|
||||
// queued_scope = scope.$new(true),
|
||||
// scheduled_scope = scope.$new(true),
|
||||
max_rows,
|
||||
user,
|
||||
html, e;
|
||||
|
||||
html = '';
|
||||
html += "<div class=\"portal-job-template-container\">\n";
|
||||
// html+= "<span id='portal-job-template-header'>Job Templates </span>";
|
||||
// html += "<ul id=\"job_status_tabs\" class=\"nav nav-tabs\">\n";
|
||||
// html += "<li class=\"active\"><a id=\"active_jobs_link\" ng-click=\"toggleTab($event, 'active_jobs_link', 'job_status_tabs')\"\n";
|
||||
// html += " href=\"#active-jobs-tab\" data-toggle=\"tab\">Jobs</a></li>\n";
|
||||
// html += "<li><a id=\"scheduled_jobs_link\" ng-click=\"toggleTab($event, 'scheduled_jobs_link', 'job_status_tabs')\"\n";
|
||||
// html += "href=\"#scheduled-jobs-tab\" data-toggle=\"tab\">Schedule</a></li>\n";
|
||||
// html += "</ul>\n";
|
||||
// html += "<div id=\"portal-job-template-tab-content\" class=\"tab-content \">\n";
|
||||
html += "<div class=\"tab-pane active\" id=\"active-jobs-tab\">\n";
|
||||
html += "<div class=\"row search-row\" id='portal-job-template-search'>\n";
|
||||
html += "<div class=\"col-lg-6 col-md-6\" id=\"active-jobs-search-container\"></div>\n";
|
||||
@ -44,8 +33,6 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
html += "<div id=\"active-jobs\" class=\"job-list-target\"></div>\n";
|
||||
html += "</div>\n"; //list
|
||||
html += "</div>\n"; //active-jobs-tab
|
||||
// html += "<div class=\"tab-pane\" id=\"scheduled-jobs-tab\"></div>\n";
|
||||
// html += "</div>\n"; // jobs-list-container
|
||||
html += "</div>\n";
|
||||
|
||||
e = angular.element(document.getElementById(target));
|
||||
@ -71,44 +58,17 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
if (PortalJobsList.fields.type) {
|
||||
PortalJobsList.fields.type.searchOptions = scope.type_choices;
|
||||
}
|
||||
user = scope.$parent.current_user.id;
|
||||
LoadJobsScope({
|
||||
parent_scope: scope,
|
||||
scope: jobs_scope,
|
||||
list: PortalJobsList,
|
||||
id: 'active-jobs',
|
||||
url: GetBasePath('unified_jobs') + '?status__in=running,completed,failed,successful,error,canceled',
|
||||
url: GetBasePath('jobs')+'?created_by='+user,
|
||||
pageSize: max_rows,
|
||||
spinner: true
|
||||
});
|
||||
|
||||
// completed_scope.showJobType = true;
|
||||
// LoadJobsScope({
|
||||
// parent_scope: scope,
|
||||
// scope: completed_scope,
|
||||
// list: PortalJobsList,
|
||||
// id: 'active-jobs',
|
||||
// url: GetBasePath('unified_jobs') + '?or__status=successful&or__status=failed&or__status=error&or__status=canceled',
|
||||
// // searchParams: search_params,
|
||||
// pageSize: max_rows
|
||||
// });
|
||||
|
||||
// LoadJobsScope({
|
||||
// parent_scope: scope,
|
||||
// scope: running_scope,
|
||||
// list: PortalJobsList,
|
||||
// id: 'active-jobs',
|
||||
// url: GetBasePath('unified_jobs') + '?status=running',
|
||||
// pageSize: max_rows
|
||||
// });
|
||||
|
||||
// LoadJobsScope({
|
||||
// parent_scope: scope,
|
||||
// scope: queued_scope,
|
||||
// list: PortalJobsList,
|
||||
// id: 'active-jobs',
|
||||
// url: GetBasePath('unified_jobs') + '?or__status=pending&or__status=waiting&or__status=new',
|
||||
// pageSize: max_rows
|
||||
// });
|
||||
|
||||
$(window).resize(_.debounce(function() {
|
||||
resizePortalJobsWidget();
|
||||
|
||||
@ -64,7 +64,16 @@ angular.module('AuthService', ['ngCookies', 'Utilities'])
|
||||
//$rootScope.$destroy();
|
||||
$cookieStore.remove('token_expires');
|
||||
$cookieStore.remove('current_user');
|
||||
$cookieStore.remove('lastPath');
|
||||
|
||||
if($cookieStore.get('lastPath')==='/portal'){
|
||||
$cookieStore.put( 'lastPath', '/portal');
|
||||
$rootScope.lastPath = '/portal';
|
||||
}
|
||||
else {
|
||||
$cookieStore.remove('lastPath');
|
||||
$rootScope.lastPath = '/home';
|
||||
}
|
||||
|
||||
$cookieStore.remove('token');
|
||||
$cookieStore.put('userLoggedIn', false);
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
@ -75,7 +84,6 @@ angular.module('AuthService', ['ngCookies', 'Utilities'])
|
||||
$rootScope.sessionExpired = false;
|
||||
$rootScope.token = null;
|
||||
$rootScope.token_expires = null;
|
||||
$rootScope.lastPath = '/home';
|
||||
$rootScope.login_username = null;
|
||||
$rootScope.login_password = null;
|
||||
},
|
||||
|
||||
@ -28,7 +28,6 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
endpoint = params.endpoint,
|
||||
protocol = $location.protocol(),
|
||||
config, socketPort,
|
||||
// handshakeData,
|
||||
url;
|
||||
|
||||
// Since some pages are opened in a new tab, we might get here before AnsibleConfig is available.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user