Merge branch 'master' into expunge-zeromq-unstable

Conflicts:
	setup/roles/awx_install/handlers/main.yml
This commit is contained in:
Luke Sneeringer 2014-11-10 08:47:08 -06:00
commit 0e8121f7f1
17 changed files with 202 additions and 169 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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?

View File

@ -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

View File

@ -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')

View File

@ -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():

View File

@ -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 --
# ----------------

View File

@ -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();
}
]);

View File

@ -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:

View File

@ -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':

View File

@ -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) {

View File

@ -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);
}

View File

@ -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') {

View File

@ -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'
}

View File

@ -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();

View File

@ -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;
},

View File

@ -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.