diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index e2e7b87a7e..03a775ce42 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -103,7 +103,7 @@ angular.module('ansible', [ $routeProvider. when('/jobs', { templateUrl: urlPrefix + 'partials/jobs.html', - controller: 'JobsListCtrl' + controller: 'JobsList' }). when('/jobs/:id', { diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index ecbf8d86e5..452651fd52 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -4,426 +4,51 @@ * * Jobs.js * - * Controller functions for the Job model. + * Controller functions for the Inventory model. * */ - + 'use strict'; -function JobsListCtrl($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList, GenerateList, LoadBreadCrumbs, Prompt, - SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh, - JobStatusToolTip, Empty, Wait) { - +function JobsList($scope, $compile, ClearScope, Breadcrumbs, LoadScope, JobList) { + ClearScope(); - var list = JobList, - defaultUrl = GetBasePath('jobs'), - generator = GenerateList, - opt; - - generator.inject(list, { mode: 'edit', scope: $scope }); + var e, completed_scope, running_scope, queued_scope, schedule_scope, + completed_list, running_list, queued_list, schedule_list; - $rootScope.flashMessage = null; - $scope.selected = []; + // Add breadcrumbs + e = angular.element(document.getElementById('breadcrumbs')); + e.html(Breadcrumbs({ list: JobList, mode: 'edit' })); + $compile(e)($scope); - if ($scope.removePostRefresh) { - $scope.removePostRefresh(); - } - $scope.removePostRefresh = $scope.$on('PostRefresh', function () { - var i, cDate; - $("tr.success").each(function () { - // Make sure no rows have a green background - var ngc = $(this).attr('ng-class'); - $scope[ngc] = ""; - }); - if ($scope.jobs && $scope.jobs.length) { - for (i = 0; i < $scope.jobs.length; i++) { - // Convert created date to local time zone - cDate = new Date($scope.jobs[i].created); - $scope.jobs[i].created = FormatDate(cDate); - // Set tooltip and link - $scope.jobs[i].statusBadgeToolTip = JobStatusToolTip($scope.jobs[i].status) + - " Click to view status details."; - $scope.jobs[i].statusLinkTo = '/#/jobs/' + $scope.jobs[i].id; - } - } + completed_list = angular.copy(JobList); + completed_list.name = "completed_jobs"; + completed_list.iterator = "completed_jobs"; + completed_list.editTitle = "Completed"; + completed_scope = $scope.$new(); + LoadScope({ + scope: completed_scope, + list: completed_list, + id: 'completed_jobs', + url: '/api/v1/jobs' }); - if ($routeParams.job_host_summaries__host) { - defaultUrl += '?job_host_summaries__host=' + $routeParams.job_host_summaries__host; - } else if ($routeParams.inventory__int && $routeParams.status) { - defaultUrl += '?inventory__int=' + $routeParams.inventory__int + '&status=' + - $routeParams.status; - } - SearchInit({ - scope: $scope, - set: 'jobs', - list: list, - url: defaultUrl - }); - PaginateInit({ - scope: $scope, - list: list, - url: defaultUrl + running_list = angular.copy(JobList); + running_list.name = "running_jobs"; + running_list.iterator = "running_job"; + running_list.editTitle = "Running"; + running_scope = $scope.$new(); + LoadScope({ + scope: running_scope, + list: running_list, + id: 'running_jobs', + url: '/api/v1/jobs' }); - // Called from Inventories page, failed jobs link. Find jobs for selected inventory. - if ($routeParams.inventory__int) { - $scope[list.iterator + 'SearchField'] = 'inventory'; - $scope[list.iterator + 'SearchValue'] = $routeParams.inventory__int; - $scope[list.iterator + 'SearchFieldLabel'] = 'Inventory ID'; - } - if ($routeParams.id__int) { - $scope[list.iterator + 'SearchField'] = 'id'; - $scope[list.iterator + 'SearchValue'] = $routeParams.id__int; - $scope[list.iterator + 'SearchFieldLabel'] = 'Job ID'; - } - if ($routeParams.status) { - $scope[list.iterator + 'SearchField'] = 'status'; - $scope[list.iterator + 'SelectShow'] = true; - $scope[list.iterator + 'SearchSelectOpts'] = list.fields.status.searchOptions; - $scope[list.iterator + 'SearchFieldLabel'] = list.fields.status.label.replace(/
/g, ' '); - for (opt in list.fields.status.searchOptions) { - if (list.fields.status.searchOptions[opt].value === $routeParams.status) { - $scope[list.iterator + 'SearchSelectValue'] = list.fields.status.searchOptions[opt]; - break; - } - } - } - - $scope.search(list.iterator); - - LoadBreadCrumbs(); - - $scope.refresh = function () { - Wait('start'); - $scope.jobLoading = false; - Refresh({ scope: $scope, set: 'jobs', iterator: 'job', url: $scope.current_url }); - }; - - $scope.refreshJob = $scope.refresh; - - $scope.editJob = function (id, name) { - LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); - $location.path($location.path() + '/' + id); - }; - - $scope.viewEvents = function (id, name) { - LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); - $location.path($location.path() + '/' + id + '/job_events'); - }; - - $scope.viewSummary = function (id, name) { - LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); - $location.path($location.path() + '/' + id + '/job_host_summaries'); - }; - - $scope.deleteJob = function (id) { - Rest.setUrl(defaultUrl + id + '/'); - Rest.get() - .success(function (data) { - - var action, url, action_label, hdr; - - if (data.status === 'pending' || data.status === 'running' || data.status === 'waiting') { - url = data.related.cancel; - action_label = 'cancel'; - hdr = 'Cancel Job'; - } else { - url = defaultUrl + id + '/'; - action_label = 'delete'; - hdr = 'Delete Job'; - } - - action = function () { - Rest.setUrl(url); - if (action_label === 'cancel') { - Rest.post() - .success(function () { - $('#prompt-modal').modal('hide'); - $scope.search(list.iterator); - }) - .error(function (data, status) { - $('#prompt-modal').modal('hide'); - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + - ' failed. POST returned status: ' + status }); - }); - } else { - Rest.destroy() - .success(function () { - $('#prompt-modal').modal('hide'); - $scope.search(list.iterator); - }) - .error(function (data, status) { - $('#prompt-modal').modal('hide'); - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + - ' failed. DELETE returned status: ' + status }); - }); - } - }; - - Prompt({ - hdr: hdr, - body: 'Are you sure you want to ' + action_label + ' job ' + id + '?', - action: action - }); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get job details. GET returned status: ' + status }); - }); - }; - - $scope.submitJob = function (id, template) { - SubmitJob({ scope: $scope, id: id, template: template }); - }; } -JobsListCtrl.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList', - 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', - 'ProcessErrors', 'GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh', 'JobStatusToolTip', - 'Empty', 'Wait' -]; +JobsList.$inject = ['$scope', '$compile', 'ClearScope', 'Breadcrumbs', 'LoadScope', 'JobList']; -function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest, - Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, - CredentialList, ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip, Wait, Empty, - ParseVariableString) { - ClearScope(); - - var defaultUrl = GetBasePath('jobs'), - generator = GenerateForm, - id = $routeParams.id, - loadingFinishedCount = 0, - templateForm = {}; - - generator.inject(JobForm, { mode: 'edit', related: true, scope: $scope }); - - $scope.job_id = id; - $scope.parseType = 'yaml'; - $scope.statusSearchSpin = false; - $scope.disableParseSelection = true; - - function getPlaybooks(project, playbook) { - if (!Empty(project)) { - var url = GetBasePath('projects') + project + '/playbooks/'; - Rest.setUrl(url); - Rest.get() - .success(function (data) { - var i; - $scope.playbook_options = []; - for (i = 0; i < data.length; i++) { - $scope.playbook_options.push(data[i]); - } - for (i = 0; i < $scope.playbook_options.length; i++) { - if ($scope.playbook_options[i] === playbook) { - $scope.playbook = $scope.playbook_options[i]; - } - } - $scope.$emit('jobTemplateLoadFinished'); - }) - .error(function () { - $scope.$emit('jobTemplateLoadFinished'); - }); - } else { - $scope.$emit('jobTemplateLoadFinished'); - } - } - - - // Retrieve each related set and populate the playbook list - if ($scope.jobLoadedRemove) { - $scope.jobLoadedRemove(); - } - $scope.jobLoadedRemove = $scope.$on('jobLoaded', function (e, related_cloud_credential, project, playbook) { - - getPlaybooks(project, playbook); - - //$scope[form.name + 'ReadOnly'] = ($scope.status === 'new') ? false : true; - - //$('#forks-slider').slider("option", "value", $scope.forks); - //$('#forks-slider').slider("disable"); - //$('input[type="checkbox"]').attr('disabled', 'disabled'); - //$('input[type="radio"]').attr('disabled', 'disabled'); - //$('#host_config_key-gen-btn').attr('disabled', 'disabled'); - //$('textarea').attr('readonly', 'readonly'); - - // Get job template and display/hide host callback fields - /*Rest.setUrl($scope.template_url); - Rest.get() - .success(function (data) { - var dft = (data.host_config_key) ? 'true' : 'false'; - $scope.host_config_key = data.host_config_key; - md5Setup({ - scope: $scope, - master: master, - check_field: 'allow_callbacks', - default_val: dft - }); - $scope.callback_url = (data.related) ? data.related.callback : '<< Job template not found >>'; - $scope.$emit('jobTemplateLoadFinished'); - }) - .error(function () { - Wait('stop'); - $scope.callback_url = '<< Job template not found >>'; - }); - */ - if (related_cloud_credential) { - //Get the name of the cloud credential - Rest.setUrl(related_cloud_credential); - Rest.get() - .success(function (data) { - $scope.cloud_credential_name = data.name; - $scope.$emit('jobTemplateLoadFinished'); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to related cloud credential. GET returned status: ' + status }); - }); - } else { - $scope.$emit('jobTemplateLoadFinished'); - } - - }); - - // Turn off 'Wait' after both cloud credential and playbook list come back - if ($scope.removeJobTemplateLoadFinished) { - $scope.removeJobTemplateLoadFinished(); - } - $scope.removeJobTemplateLoadFinished = $scope.$on('jobTemplateLoadFinished', function () { - loadingFinishedCount++; - if (loadingFinishedCount >= 2) { - // The initial template load finished. Now load related jobs, which - // will turn off the 'working' spinner. - Wait('stop'); - } - }); - - // Our job type options - $scope.job_type_options = [{ - value: 'run', - label: 'Run' - }, { - value: 'check', - label: 'Check' - }]; - $scope.verbosity_options = [{ - value: 0, - label: 'Default' - }, { - value: 1, - label: 'Verbose' - }, { - value: 3, - label: 'Debug' - }]; - $scope.playbook_options = null; - $scope.playbook = null; - - function calcRows(content) { - var n = content.match(/\n/g), - rows = (n) ? n.length : 1; - return (rows > 15) ? 15 : rows; - } - - // Retrieve detail record and prepopulate the form - Wait('start'); - Rest.setUrl(defaultUrl + ':id/'); - Rest.get({ params: { id: id } }) - .success(function (data) { - - var i, fld; - - LoadBreadCrumbs(); - - $scope.status = data.status; - $scope.created = FormatDate(data.created); - $scope.result_stdout = data.result_stdout; - $scope.result_traceback = data.result_traceback; - $scope.stdout_rows = calcRows($scope.result_stdout); - $scope.traceback_rows = calcRows($scope.result_traceback); - - // Now load the job template form - templateForm.addTitle = 'Create Job Templates'; - templateForm.editTitle = '{{ name }}'; - templateForm.name = 'job_templates'; - templateForm.twoColumns = true; - templateForm.fields = angular.copy(JobTemplateForm.fields); - for (fld in templateForm.fields) { - templateForm.fields[fld].readonly = true; - } - - $('#ui-accordion-jobs-collapse-0-panel-1').find('div').attr('id','job-template-container'); - generator.inject(templateForm, { mode: 'edit', id: 'job-template-container', scope: $scope, breadCrumbs: false }); - - for (fld in templateForm.fields) { - if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) { - if (JobTemplateForm.fields[fld].type === 'select') { - if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) { - for (i = 0; i < $scope[fld + '_options'].length; i++) { - if (data[fld] === $scope[fld + '_options'][i].value) { - $scope[fld] = $scope[fld + '_options'][i]; - } - } - } else { - $scope[fld] = data[fld]; - } - } else { - $scope[fld] = data[fld]; - } - } - if (fld === 'variables') { - $scope.variables = ParseVariableString(data.extra_vars); - } - if (JobTemplateForm.fields[fld].type === 'lookup' && data.summary_fields[JobTemplateForm.fields[fld].sourceModel]) { - $scope[JobTemplateForm.fields[fld].sourceModel + '_' + JobTemplateForm.fields[fld].sourceField] = - data.summary_fields[JobTemplateForm.fields[fld].sourceModel][JobTemplateForm.fields[fld].sourceField]; - } - } - - $scope.id = data.id; - $scope.name = (data.summary_fields && data.summary_fields.job_template) ? data.summary_fields.job_template.name : ''; - $scope.statusToolTip = JobStatusToolTip(data.status); - $scope.url = data.url; - $scope.project = data.project; - - $scope.$emit('jobLoaded', data.related.cloud_credential, data.project, data.playbook); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status }); - }); - - $scope.refresh = function () { - Wait('start'); - Rest.setUrl(defaultUrl + id + '/'); - Rest.get() - .success(function (data) { - $scope.status = data.status; - $scope.result_stdout = data.result_stdout; - $scope.result_traceback = data.result_traceback; - $scope.stdout_rows = calcRows($scope.result_stdout); - $scope.traceback_rows = calcRows($scope.result_traceback); - Wait('stop'); - }) - .error(function (data, status) { - ProcessErrors($scope, data, status, null, { hdr: 'Error!', - msg: 'Attempt to load job failed. GET returned status: ' + status }); - }); - }; - - $scope.jobSummary = function () { - $location.path('/jobs/' + id + '/job_host_summaries'); - }; - - $scope.jobEvents = function () { - $location.path('/jobs/' + id + '/job_events'); - }; -} - -JobsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', 'JobTemplateForm', - 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', - 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords', - 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString' -]; diff --git a/awx/ui/static/js/controllers/Jobs.js.old b/awx/ui/static/js/controllers/Jobs.js.old new file mode 100644 index 0000000000..ecbf8d86e5 --- /dev/null +++ b/awx/ui/static/js/controllers/Jobs.js.old @@ -0,0 +1,429 @@ +/************************************ + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * + * Jobs.js + * + * Controller functions for the Job model. + * + */ + +'use strict'; + +function JobsListCtrl($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList, GenerateList, LoadBreadCrumbs, Prompt, + SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, GetBasePath, LookUpInit, SubmitJob, FormatDate, Refresh, + JobStatusToolTip, Empty, Wait) { + + ClearScope(); + + var list = JobList, + defaultUrl = GetBasePath('jobs'), + generator = GenerateList, + opt; + + generator.inject(list, { mode: 'edit', scope: $scope }); + + $rootScope.flashMessage = null; + $scope.selected = []; + + if ($scope.removePostRefresh) { + $scope.removePostRefresh(); + } + $scope.removePostRefresh = $scope.$on('PostRefresh', function () { + var i, cDate; + $("tr.success").each(function () { + // Make sure no rows have a green background + var ngc = $(this).attr('ng-class'); + $scope[ngc] = ""; + }); + if ($scope.jobs && $scope.jobs.length) { + for (i = 0; i < $scope.jobs.length; i++) { + // Convert created date to local time zone + cDate = new Date($scope.jobs[i].created); + $scope.jobs[i].created = FormatDate(cDate); + // Set tooltip and link + $scope.jobs[i].statusBadgeToolTip = JobStatusToolTip($scope.jobs[i].status) + + " Click to view status details."; + $scope.jobs[i].statusLinkTo = '/#/jobs/' + $scope.jobs[i].id; + } + } + }); + + if ($routeParams.job_host_summaries__host) { + defaultUrl += '?job_host_summaries__host=' + $routeParams.job_host_summaries__host; + } else if ($routeParams.inventory__int && $routeParams.status) { + defaultUrl += '?inventory__int=' + $routeParams.inventory__int + '&status=' + + $routeParams.status; + } + SearchInit({ + scope: $scope, + set: 'jobs', + list: list, + url: defaultUrl + }); + PaginateInit({ + scope: $scope, + list: list, + url: defaultUrl + }); + + // Called from Inventories page, failed jobs link. Find jobs for selected inventory. + if ($routeParams.inventory__int) { + $scope[list.iterator + 'SearchField'] = 'inventory'; + $scope[list.iterator + 'SearchValue'] = $routeParams.inventory__int; + $scope[list.iterator + 'SearchFieldLabel'] = 'Inventory ID'; + } + if ($routeParams.id__int) { + $scope[list.iterator + 'SearchField'] = 'id'; + $scope[list.iterator + 'SearchValue'] = $routeParams.id__int; + $scope[list.iterator + 'SearchFieldLabel'] = 'Job ID'; + } + if ($routeParams.status) { + $scope[list.iterator + 'SearchField'] = 'status'; + $scope[list.iterator + 'SelectShow'] = true; + $scope[list.iterator + 'SearchSelectOpts'] = list.fields.status.searchOptions; + $scope[list.iterator + 'SearchFieldLabel'] = list.fields.status.label.replace(/
/g, ' '); + for (opt in list.fields.status.searchOptions) { + if (list.fields.status.searchOptions[opt].value === $routeParams.status) { + $scope[list.iterator + 'SearchSelectValue'] = list.fields.status.searchOptions[opt]; + break; + } + } + } + + $scope.search(list.iterator); + + LoadBreadCrumbs(); + + $scope.refresh = function () { + Wait('start'); + $scope.jobLoading = false; + Refresh({ scope: $scope, set: 'jobs', iterator: 'job', url: $scope.current_url }); + }; + + $scope.refreshJob = $scope.refresh; + + $scope.editJob = function (id, name) { + LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); + $location.path($location.path() + '/' + id); + }; + + $scope.viewEvents = function (id, name) { + LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); + $location.path($location.path() + '/' + id + '/job_events'); + }; + + $scope.viewSummary = function (id, name) { + LoadBreadCrumbs({ path: '/jobs/' + id, title: id + ' - ' + name }); + $location.path($location.path() + '/' + id + '/job_host_summaries'); + }; + + $scope.deleteJob = function (id) { + Rest.setUrl(defaultUrl + id + '/'); + Rest.get() + .success(function (data) { + + var action, url, action_label, hdr; + + if (data.status === 'pending' || data.status === 'running' || data.status === 'waiting') { + url = data.related.cancel; + action_label = 'cancel'; + hdr = 'Cancel Job'; + } else { + url = defaultUrl + id + '/'; + action_label = 'delete'; + hdr = 'Delete Job'; + } + + action = function () { + Rest.setUrl(url); + if (action_label === 'cancel') { + Rest.post() + .success(function () { + $('#prompt-modal').modal('hide'); + $scope.search(list.iterator); + }) + .error(function (data, status) { + $('#prompt-modal').modal('hide'); + ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + + ' failed. POST returned status: ' + status }); + }); + } else { + Rest.destroy() + .success(function () { + $('#prompt-modal').modal('hide'); + $scope.search(list.iterator); + }) + .error(function (data, status) { + $('#prompt-modal').modal('hide'); + ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Call to ' + url + + ' failed. DELETE returned status: ' + status }); + }); + } + }; + + Prompt({ + hdr: hdr, + body: 'Are you sure you want to ' + action_label + ' job ' + id + '?', + action: action + }); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get job details. GET returned status: ' + status }); + }); + }; + + $scope.submitJob = function (id, template) { + SubmitJob({ scope: $scope, id: id, template: template }); + }; +} + +JobsListCtrl.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobList', + 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', + 'ProcessErrors', 'GetBasePath', 'LookUpInit', 'SubmitJob', 'FormatDate', 'Refresh', 'JobStatusToolTip', + 'Empty', 'Wait' +]; + + +function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobForm, JobTemplateForm, GenerateForm, Rest, + Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, + CredentialList, ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip, Wait, Empty, + ParseVariableString) { + + ClearScope(); + + var defaultUrl = GetBasePath('jobs'), + generator = GenerateForm, + id = $routeParams.id, + loadingFinishedCount = 0, + templateForm = {}; + + generator.inject(JobForm, { mode: 'edit', related: true, scope: $scope }); + + $scope.job_id = id; + $scope.parseType = 'yaml'; + $scope.statusSearchSpin = false; + $scope.disableParseSelection = true; + + function getPlaybooks(project, playbook) { + if (!Empty(project)) { + var url = GetBasePath('projects') + project + '/playbooks/'; + Rest.setUrl(url); + Rest.get() + .success(function (data) { + var i; + $scope.playbook_options = []; + for (i = 0; i < data.length; i++) { + $scope.playbook_options.push(data[i]); + } + for (i = 0; i < $scope.playbook_options.length; i++) { + if ($scope.playbook_options[i] === playbook) { + $scope.playbook = $scope.playbook_options[i]; + } + } + $scope.$emit('jobTemplateLoadFinished'); + }) + .error(function () { + $scope.$emit('jobTemplateLoadFinished'); + }); + } else { + $scope.$emit('jobTemplateLoadFinished'); + } + } + + + // Retrieve each related set and populate the playbook list + if ($scope.jobLoadedRemove) { + $scope.jobLoadedRemove(); + } + $scope.jobLoadedRemove = $scope.$on('jobLoaded', function (e, related_cloud_credential, project, playbook) { + + getPlaybooks(project, playbook); + + //$scope[form.name + 'ReadOnly'] = ($scope.status === 'new') ? false : true; + + //$('#forks-slider').slider("option", "value", $scope.forks); + //$('#forks-slider').slider("disable"); + //$('input[type="checkbox"]').attr('disabled', 'disabled'); + //$('input[type="radio"]').attr('disabled', 'disabled'); + //$('#host_config_key-gen-btn').attr('disabled', 'disabled'); + //$('textarea').attr('readonly', 'readonly'); + + // Get job template and display/hide host callback fields + /*Rest.setUrl($scope.template_url); + Rest.get() + .success(function (data) { + var dft = (data.host_config_key) ? 'true' : 'false'; + $scope.host_config_key = data.host_config_key; + md5Setup({ + scope: $scope, + master: master, + check_field: 'allow_callbacks', + default_val: dft + }); + $scope.callback_url = (data.related) ? data.related.callback : '<< Job template not found >>'; + $scope.$emit('jobTemplateLoadFinished'); + }) + .error(function () { + Wait('stop'); + $scope.callback_url = '<< Job template not found >>'; + }); + */ + if (related_cloud_credential) { + //Get the name of the cloud credential + Rest.setUrl(related_cloud_credential); + Rest.get() + .success(function (data) { + $scope.cloud_credential_name = data.name; + $scope.$emit('jobTemplateLoadFinished'); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to related cloud credential. GET returned status: ' + status }); + }); + } else { + $scope.$emit('jobTemplateLoadFinished'); + } + + }); + + // Turn off 'Wait' after both cloud credential and playbook list come back + if ($scope.removeJobTemplateLoadFinished) { + $scope.removeJobTemplateLoadFinished(); + } + $scope.removeJobTemplateLoadFinished = $scope.$on('jobTemplateLoadFinished', function () { + loadingFinishedCount++; + if (loadingFinishedCount >= 2) { + // The initial template load finished. Now load related jobs, which + // will turn off the 'working' spinner. + Wait('stop'); + } + }); + + // Our job type options + $scope.job_type_options = [{ + value: 'run', + label: 'Run' + }, { + value: 'check', + label: 'Check' + }]; + $scope.verbosity_options = [{ + value: 0, + label: 'Default' + }, { + value: 1, + label: 'Verbose' + }, { + value: 3, + label: 'Debug' + }]; + $scope.playbook_options = null; + $scope.playbook = null; + + function calcRows(content) { + var n = content.match(/\n/g), + rows = (n) ? n.length : 1; + return (rows > 15) ? 15 : rows; + } + + // Retrieve detail record and prepopulate the form + Wait('start'); + Rest.setUrl(defaultUrl + ':id/'); + Rest.get({ params: { id: id } }) + .success(function (data) { + + var i, fld; + + LoadBreadCrumbs(); + + $scope.status = data.status; + $scope.created = FormatDate(data.created); + $scope.result_stdout = data.result_stdout; + $scope.result_traceback = data.result_traceback; + $scope.stdout_rows = calcRows($scope.result_stdout); + $scope.traceback_rows = calcRows($scope.result_traceback); + + // Now load the job template form + templateForm.addTitle = 'Create Job Templates'; + templateForm.editTitle = '{{ name }}'; + templateForm.name = 'job_templates'; + templateForm.twoColumns = true; + templateForm.fields = angular.copy(JobTemplateForm.fields); + for (fld in templateForm.fields) { + templateForm.fields[fld].readonly = true; + } + + $('#ui-accordion-jobs-collapse-0-panel-1').find('div').attr('id','job-template-container'); + generator.inject(templateForm, { mode: 'edit', id: 'job-template-container', scope: $scope, breadCrumbs: false }); + + for (fld in templateForm.fields) { + if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) { + if (JobTemplateForm.fields[fld].type === 'select') { + if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) { + for (i = 0; i < $scope[fld + '_options'].length; i++) { + if (data[fld] === $scope[fld + '_options'][i].value) { + $scope[fld] = $scope[fld + '_options'][i]; + } + } + } else { + $scope[fld] = data[fld]; + } + } else { + $scope[fld] = data[fld]; + } + } + if (fld === 'variables') { + $scope.variables = ParseVariableString(data.extra_vars); + } + if (JobTemplateForm.fields[fld].type === 'lookup' && data.summary_fields[JobTemplateForm.fields[fld].sourceModel]) { + $scope[JobTemplateForm.fields[fld].sourceModel + '_' + JobTemplateForm.fields[fld].sourceField] = + data.summary_fields[JobTemplateForm.fields[fld].sourceModel][JobTemplateForm.fields[fld].sourceField]; + } + } + + $scope.id = data.id; + $scope.name = (data.summary_fields && data.summary_fields.job_template) ? data.summary_fields.job_template.name : ''; + $scope.statusToolTip = JobStatusToolTip(data.status); + $scope.url = data.url; + $scope.project = data.project; + + $scope.$emit('jobLoaded', data.related.cloud_credential, data.project, data.playbook); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to retrieve job: ' + $routeParams.id + '. GET status: ' + status }); + }); + + $scope.refresh = function () { + Wait('start'); + Rest.setUrl(defaultUrl + id + '/'); + Rest.get() + .success(function (data) { + $scope.status = data.status; + $scope.result_stdout = data.result_stdout; + $scope.result_traceback = data.result_traceback; + $scope.stdout_rows = calcRows($scope.result_stdout); + $scope.traceback_rows = calcRows($scope.result_traceback); + Wait('stop'); + }) + .error(function (data, status) { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', + msg: 'Attempt to load job failed. GET returned status: ' + status }); + }); + }; + + $scope.jobSummary = function () { + $location.path('/jobs/' + id + '/job_host_summaries'); + }; + + $scope.jobEvents = function () { + $location.path('/jobs/' + id + '/job_events'); + }; +} + +JobsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobForm', 'JobTemplateForm', + 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', + 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords', + 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString' +]; diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js index 0ac79b2560..9501103586 100644 --- a/awx/ui/static/js/helpers/Jobs.js +++ b/awx/ui/static/js/helpers/Jobs.js @@ -158,4 +158,42 @@ angular.module('JobsHelper', ['Utilities', 'FormGenerator', 'JobSummaryDefinitio }; } -]); \ No newline at end of file +]) + +/** + * + * Called from JobsList controller to load each section or list on the page + * + */ +.factory('LoadScope', ['SearchInit', 'PaginateInit', 'GenerateList', function(SearchInit, PaginateInit, GenerateList) { + return function(params) { + var scope = params.scope, + list = params.list, + id = params.id, + url = params.url; + + GenerateList.inject(list, { + mode: 'edit', + id: id, + breadCrumbs: false, + scope: scope, + searchSize: 'col-lg-4 col-md-6 col-sm-12 col-xs-12', + showSearch: false + }); + + url = '/static/sample/data/schedules/inventory/data.json'; + SearchInit({ + scope: scope, + set: list.name, + list: list, + url: url + }); + + PaginateInit({ + scope: scope, + list: list, + url: url, + pageSize: 10 + }); + }; +}]); \ No newline at end of file diff --git a/awx/ui/static/js/lists/Jobs.js b/awx/ui/static/js/lists/Jobs.js index 6d746d4a54..c246501505 100644 --- a/awx/ui/static/js/lists/Jobs.js +++ b/awx/ui/static/js/lists/Jobs.js @@ -15,8 +15,10 @@ angular.module('JobsListDefinition', []) name: 'jobs', iterator: 'job', editTitle: 'Jobs', + showTitle: true, index: false, hover: true, + well: false, "class": 'jobs-table', fields: { diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index b8a55d9ad9..6253163c2c 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -142,7 +142,6 @@ a:focus { } #home_groups_table .actions .cancel { padding-right: 3px; } -#jobs_table .actions .cancel { padding-right: 10px; } .success-badge { color: #ffffff; @@ -991,13 +990,6 @@ input[type="checkbox"].checkbox-no-label { content: "\f111"; } - /*.icon-failures-none, - .icon-failures-na, - .icon-failures-true, - .icon-failures-false { - font-size: 12px; - }*/ - .badge { padding: 2px 3px 3px 4px; font-size: 10px; @@ -1005,6 +997,18 @@ input[type="checkbox"].checkbox-no-label { line-height: 1; } + .job_list { + padding-left: 15px; + padding-right: 15px; + margin-top: 30px; + + .form-title { + padding-left: 8px; + } + } + + + /* Inventory job status badge */ .failures-true { background-color: @red; diff --git a/awx/ui/static/lib/ansible/list-generator.js b/awx/ui/static/lib/ansible/list-generator.js index 7378592b39..17efee59ef 100644 --- a/awx/ui/static/lib/ansible/list-generator.js +++ b/awx/ui/static/lib/ansible/list-generator.js @@ -166,102 +166,104 @@ angular.module('ListGenerator', ['GeneratorHelpers']) html += "
\n"; - if (list.name !== 'groups') { - if (options.searchSize) { - html += SearchWidget({ - iterator: list.iterator, - template: list, - mini: true, - size: options.searchSize, - searchWidgets: list.searchWidgets - }); - } else if (options.mode === 'summary') { - html += SearchWidget({ - iterator: list.iterator, - template: list, - mini: true, - size: 'col-lg-6' - }); - } else if (options.mode === 'lookup' || options.id !== undefined) { - html += SearchWidget({ - iterator: list.iterator, - template: list, - mini: true, - size: 'col-lg-8' - }); - } else { - html += SearchWidget({ - iterator: list.iterator, - template: list, - mini: true - }); - } - } - - if (options.mode !== 'lookup') { - //actions - base = $location.path().replace(/^\//, '').split('/')[0]; - html += "
\n"; - - html += "
\n"; - - // Add toolbar buttons or 'actions' - for (action in list.actions) { - if (list.actions[action].mode === 'all' || list.actions[action].mode === options.mode) { - if ((list.actions[action].basePaths === undefined) || - (list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1)) { - html += this.button({ - btn: list.actions[action], - action: action, - toolbar: true - }); - } + if (options.showSearch === undefined || options.showSearch === true) { + if (list.name !== 'groups') { + if (options.searchSize) { + html += SearchWidget({ + iterator: list.iterator, + template: list, + mini: true, + size: options.searchSize, + searchWidgets: list.searchWidgets + }); + } else if (options.mode === 'summary') { + html += SearchWidget({ + iterator: list.iterator, + template: list, + mini: true, + size: 'col-lg-6' + }); + } else if (options.mode === 'lookup' || options.id !== undefined) { + html += SearchWidget({ + iterator: list.iterator, + template: list, + mini: true, + size: 'col-lg-8' + }); + } else { + html += SearchWidget({ + iterator: list.iterator, + template: list, + mini: true + }); } } - //select instructions - if (options.mode === 'select' && list.selectInstructions) { - btn = { - awPopOver: list.selectInstructions, - dataPlacement: 'left', - dataContainer: 'body', - 'class': 'btn-xs btn-help', - awToolTip: 'Click for help', - dataTitle: 'Help', - iconSize: 'fa-lg' - }; - //html += this.button(btn, 'select'); - html += this.button({ - btn: btn, - action: 'help', - toolbar: true - }); + if (options.mode !== 'lookup') { + //actions + base = $location.path().replace(/^\//, '').split('/')[0]; + html += "
\n"; + + html += "
\n"; + + // Add toolbar buttons or 'actions' + for (action in list.actions) { + if (list.actions[action].mode === 'all' || list.actions[action].mode === options.mode) { + if ((list.actions[action].basePaths === undefined) || + (list.actions[action].basePaths && list.actions[action].basePaths.indexOf(base) > -1)) { + html += this.button({ + btn: list.actions[action], + action: action, + toolbar: true + }); + } + } + } + + //select instructions + if (options.mode === 'select' && list.selectInstructions) { + btn = { + awPopOver: list.selectInstructions, + dataPlacement: 'left', + dataContainer: 'body', + 'class': 'btn-xs btn-help', + awToolTip: 'Click for help', + dataTitle: 'Help', + iconSize: 'fa-lg' + }; + //html += this.button(btn, 'select'); + html += this.button({ + btn: btn, + action: 'help', + toolbar: true + }); + } + + html += "
\n"; + html += "
\n"; + } else { + //lookup + html += "
\n"; } - html += "
\n"; - html += "
\n"; - } else { - //lookup - html += "
\n"; + html += "
\n"; } - html += "\n"; - // Add a title and optionally a close button (used on Inventory->Groups) if (options.mode !== 'lookup' && list.showTitle) { html += "
"; diff --git a/awx/ui/static/partials/jobs.html b/awx/ui/static/partials/jobs.html index 59ffb25810..59fe7bdd31 100644 --- a/awx/ui/static/partials/jobs.html +++ b/awx/ui/static/partials/jobs.html @@ -1,3 +1,17 @@
-
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/awx/ui/static/sample/data/jobs/completed/data.json b/awx/ui/static/sample/data/jobs/completed/data.json new file mode 100644 index 0000000000..e7ed330f34 --- /dev/null +++ b/awx/ui/static/sample/data/jobs/completed/data.json @@ -0,0 +1,231 @@ +{ + "count": 2, + "next": null, + "previous": null, + "results": [ + { + "id": 1, + "url": "/api/v1/jobs/1/", + "related": { + "job_host_summaries": "/api/v1/jobs/1/job_host_summaries/", + "activity_stream": "/api/v1/jobs/1/activity_stream/", + "job_events": "/api/v1/jobs/1/job_events/", + "job_template": "/api/v1/job_templates/3/", + "inventory": "/api/v1/inventories/4/", + "project": "/api/v1/projects/1/", + "credential": "/api/v1/credentials/8/", + "start": "/api/v1/jobs/1/start/", + "cancel": "/api/v1/jobs/1/cancel/" + }, + "summary_fields": { + "credential": { + "name": "ssh", + "description": "machine creds", + "kind": "ssh", + "cloud": false + }, + "job_template": { + "name": "Hello World", + "description": "" + }, + "project": { + "name": "Examples", + "description": "Ansible example project", + "status": "successful" + }, + "inventory": { + "name": "Rackspace", + "description": "", + "has_active_failures": true, + "total_hosts": 20, + "hosts_with_active_failures": 20, + "total_groups": 3, + "groups_with_active_failures": 3, + "has_inventory_sources": true, + "total_inventory_sources": 1, + "inventory_sources_with_failures": 1 + } + }, + "created": "2014-03-06T16:51:04.557Z", + "modified": "2014-03-06T16:51:14.272Z", + "job_template": 3, + "job_type": "playbook_run", + "inventory": 4, + "project": 1, + "playbook": "lamp_simple/site.yml", + "credential": 8, + "cloud_credential": null, + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\n\t\"variable1\": \"some value\",\n\t\"variable2\": \"another value\"\n}", + "job_tags": "", + "launch_type": "manual", + "status": "failed", + "failed": true, + "result_traceback": "", + "passwords_needed_to_start": [], + "job_args": "[\"ssh-agent\", \"sh\", \"-c\", \"ssh-add /tmp/tmp5N437j && ansible-playbook -i /vagrant/ansible-commander/awx/plugins/inventory/awxrest.py -u vagrant -e '{\\\"variable1\\\": \\\"some value\\\", \\\"variable2\\\": \\\"another value\\\"}' lamp_simple/site.yml\"]", + "job_cwd": "/vagrant/ansible-commander/awx/projects/_1__examples", + "job_env": { + "CELERY_LOG_REDIRECT_LEVEL": "WARNING", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "LESSOPEN": "|/usr/bin/lesspipe.sh %s", + "_MP_FORK_LOGFILE_": "", + "SSH_CLIENT": "10.0.2.2 61378 22", + "CVS_RSH": "ssh", + "LOGNAME": "vagrant", + "USER": "vagrant", + "HOME": "/home/vagrant", + "PATH": "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin", + "REST_API_TOKEN": "**********************************", + "CALLBACK_CONSUMER_PORT": "tcp://127.0.0.1:5557", + "ANSIBLE_CALLBACK_PLUGINS": "/vagrant/ansible-commander/awx/plugins/callback", + "LANG": "en_US.UTF-8", + "HISTCONTROL": "ignoredups", + "TERM": "xterm", + "SHELL": "/bin/bash", + "TZ": "America/New_York", + "_MP_FORK_LOGFORMAT_": "[%(asctime)s: %(levelname)s/%(processName)s] %(message)s", + "SHLVL": "1", + "G_BROKEN_FILENAMES": "1", + "HISTSIZE": "1000", + "CELERY_LOG_FILE": "", + "DJANGO_PROJECT_DIR": "/vagrant/ansible-commander", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "JOB_ID": "1", + "PYTHONPATH": "/vagrant/ansible-commander/awx/lib/site-packages:", + "CELERY_LOADER": "djcelery.loaders.DjangoLoader", + "_MP_FORK_LOGLEVEL_": "10", + "ANSIBLE_NOCOLOR": "1", + "JOB_CALLBACK_DEBUG": "1", + "REST_API_URL": "http://127.0.0.1:8013", + "_": "/usr/bin/nohup", + "SSH_CONNECTION": "10.0.2.2 61378 10.0.2.15 22", + "INVENTORY_HOSTVARS": "True", + "SSH_TTY": "/dev/pts/0", + "CELERY_LOG_LEVEL": "10", + "HOSTNAME": "vagrant-centos64.vagrantup.com", + "INVENTORY_ID": "4", + "PWD": "/home/vagrant", + "CELERY_LOG_REDIRECT": "1", + "DJANGO_SETTINGS_MODULE": "awx.settings.development", + "MAIL": "/var/spool/mail/vagrant", + "LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:" + } + }, + { + "id": 2, + "url": "/api/v1/jobs/2/", + "related": { + "job_host_summaries": "/api/v1/jobs/2/job_host_summaries/", + "activity_stream": "/api/v1/jobs/2/activity_stream/", + "job_events": "/api/v1/jobs/2/job_events/", + "job_template": "/api/v1/job_templates/3/", + "inventory": "/api/v1/inventories/4/", + "project": "/api/v1/projects/1/", + "credential": "/api/v1/credentials/8/", + "start": "/api/v1/jobs/2/start/", + "cancel": "/api/v1/jobs/2/cancel/" + }, + "summary_fields": { + "credential": { + "name": "ssh", + "description": "machine creds", + "kind": "ssh", + "cloud": false + }, + "job_template": { + "name": "Hello World", + "description": "" + }, + "project": { + "name": "Examples", + "description": "Ansible example project", + "status": "successful" + }, + "inventory": { + "name": "Rackspace", + "description": "", + "has_active_failures": true, + "total_hosts": 20, + "hosts_with_active_failures": 20, + "total_groups": 3, + "groups_with_active_failures": 3, + "has_inventory_sources": true, + "total_inventory_sources": 1, + "inventory_sources_with_failures": 1 + } + }, + "created": "2014-03-07T23:28:06.999Z", + "modified": "2014-03-07T23:28:16.424Z", + "job_template": 3, + "job_type": "playbook_run", + "inventory": 4, + "project": 1, + "playbook": "lamp_simple/site.yml", + "credential": 8, + "cloud_credential": null, + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\n\t\"variable1\": \"some value\",\n\t\"variable2\": \"another value\"\n}", + "job_tags": "", + "launch_type": "manual", + "status": "failed", + "failed": true, + "result_traceback": "", + "passwords_needed_to_start": [], + "job_args": "[\"ssh-agent\", \"sh\", \"-c\", \"ssh-add /tmp/tmpoeaDyc && ansible-playbook -i /vagrant/ansible-commander/awx/plugins/inventory/awxrest.py -u vagrant -e '{\\\"variable1\\\": \\\"some value\\\", \\\"variable2\\\": \\\"another value\\\"}' lamp_simple/site.yml\"]", + "job_cwd": "/vagrant/ansible-commander/awx/projects/_1__examples", + "job_env": { + "CELERY_LOG_REDIRECT_LEVEL": "WARNING", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "LESSOPEN": "|/usr/bin/lesspipe.sh %s", + "_MP_FORK_LOGFILE_": "", + "SSH_CLIENT": "10.0.2.2 61378 22", + "CVS_RSH": "ssh", + "LOGNAME": "vagrant", + "USER": "vagrant", + "HOME": "/home/vagrant", + "PATH": "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin", + "REST_API_TOKEN": "**********************************", + "CALLBACK_CONSUMER_PORT": "tcp://127.0.0.1:5557", + "ANSIBLE_CALLBACK_PLUGINS": "/vagrant/ansible-commander/awx/plugins/callback", + "LANG": "en_US.UTF-8", + "HISTCONTROL": "ignoredups", + "TERM": "xterm", + "SHELL": "/bin/bash", + "TZ": "America/New_York", + "_MP_FORK_LOGFORMAT_": "[%(asctime)s: %(levelname)s/%(processName)s] %(message)s", + "SHLVL": "1", + "G_BROKEN_FILENAMES": "1", + "HISTSIZE": "1000", + "CELERY_LOG_FILE": "", + "DJANGO_PROJECT_DIR": "/vagrant/ansible-commander", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "JOB_ID": "2", + "PYTHONPATH": "/vagrant/ansible-commander/awx/lib/site-packages:", + "CELERY_LOADER": "djcelery.loaders.DjangoLoader", + "_MP_FORK_LOGLEVEL_": "10", + "ANSIBLE_NOCOLOR": "1", + "JOB_CALLBACK_DEBUG": "1", + "REST_API_URL": "http://127.0.0.1:8013", + "_": "/usr/bin/nohup", + "SSH_CONNECTION": "10.0.2.2 61378 10.0.2.15 22", + "INVENTORY_HOSTVARS": "True", + "SSH_TTY": "/dev/pts/0", + "CELERY_LOG_LEVEL": "10", + "HOSTNAME": "vagrant-centos64.vagrantup.com", + "INVENTORY_ID": "4", + "PWD": "/home/vagrant", + "CELERY_LOG_REDIRECT": "1", + "DJANGO_SETTINGS_MODULE": "awx.settings.development", + "MAIL": "/var/spool/mail/vagrant", + "LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:" + } + } + ] +} \ No newline at end of file