From 29a8b46e2f14c5dd81334da7c12c0cb397b5247c Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Thu, 27 Mar 2014 14:21:47 -0400 Subject: [PATCH] Refactored job submission module, breaking the process of prompting for credentials and passwords into small, isolated units of work. Code can now be shared across each job type and unit tests are feasible. --- awx/ui/static/js/controllers/JobTemplates.js | 8 +- awx/ui/static/js/helpers/JobSubmission.js | 554 +++++++++---------- awx/ui/static/js/helpers/Jobs.js | 15 +- awx/ui/static/js/helpers/Lookup.js | 11 +- awx/ui/templates/ui/index.html | 4 +- 5 files changed, 271 insertions(+), 321 deletions(-) diff --git a/awx/ui/static/js/controllers/JobTemplates.js b/awx/ui/static/js/controllers/JobTemplates.js index 4a684d5276..ae200f1c4a 100644 --- a/awx/ui/static/js/controllers/JobTemplates.js +++ b/awx/ui/static/js/controllers/JobTemplates.js @@ -12,7 +12,7 @@ function JobTemplatesList($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobTemplateList, GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors, - GetBasePath, PromptPasswords, JobTemplateForm, CredentialList, LookUpInit, SubmitJob, Wait, Stream) { + GetBasePath, JobTemplateForm, CredentialList, LookUpInit, PlaybookRun, Wait, Stream) { ClearScope(); @@ -96,14 +96,14 @@ function JobTemplatesList($scope, $rootScope, $location, $log, $routeParams, Res }; $scope.submitJob = function (id) { - SubmitJob({ scope: $scope, id: id }); + PlaybookRun({ scope: $scope, id: id }); }; } JobTemplatesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobTemplateList', 'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope', - 'ProcessErrors', 'GetBasePath', 'PromptPasswords', 'JobTemplateForm', 'CredentialList', 'LookUpInit', - 'SubmitJob', 'Wait', 'Stream' + 'ProcessErrors', 'GetBasePath', 'JobTemplateForm', 'CredentialList', 'LookUpInit', + 'PlaybookRun', 'Wait', 'Stream' ]; function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index ebfe5cc49b..fd5367f44d 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -7,149 +7,110 @@ 'use strict'; -angular.module('JobSubmissionHelper', ['RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition', - 'LookUpHelper', 'ProjectFormDefinition', 'JobSubmissionHelper' -]) +angular.module('JobSubmissionHelper', [ 'RestServices', 'Utilities', 'CredentialFormDefinition', 'CredentialsListDefinition', + 'LookUpHelper', 'JobSubmissionHelper' ]) -.factory('PromptPasswords', ['CredentialForm', 'JobTemplateForm', '$compile', 'Rest', '$location', 'ProcessErrors', - 'GetBasePath', 'Alert', 'Empty', 'Wait', - function (CredentialForm, JobTemplateForm, $compile, Rest, $location, ProcessErrors, GetBasePath, Alert, Empty, Wait) { - return function (params) { +.factory('LaunchJob', ['Rest', 'Wait', 'ProcessErrors', function(Rest, Wait, ProcessErrors) { + return function(params) { + var scope = params.scope, + passwords = params.passwords || {}, + callback = params.callback || 'JobLaunched', + url = params.url; + + Wait('start'); + Rest.setUrl(url); + Rest.post(passwords) + .success(function () { + scope.$emit(callback); + }) + .error(function (data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Attempt to start job at ' + url + ' failed. POST returned: ' + status }); + }); + }; +}]) - var scope = params.scope, +.factory('PromptForCredential', ['Wait', 'GetBasePath', 'LookUpInit', 'JobTemplateForm', 'CredentialList', +function(Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList) { + return function(params) { + + var scope = params.scope, + callback = params.callback || 'CredentialReady', + selectionMade; + + Wait('stop'); + scope.credential = ''; + + selectionMade = function () { + scope.$emit(callback, scope.credential); + }; + + LookUpInit({ + url: GetBasePath('credentials') + '?kind=ssh', + scope: scope, + form: JobTemplateForm, + current_item: null, + list: CredentialList, + field: 'credential', + hdr: 'Credential Required', + instructions: "Launching this job requires a machine credential. Please select your machine credential now or Cancel to quit.", + postAction: selectionMade + }); + scope.lookUpCredential(); + }; +}]) + +.factory('PromptForPasswords', ['$compile', 'Wait', 'Alert', 'CredentialForm', + function($compile, Wait, Alert, CredentialForm) { + return function(params) { + var parent_scope = params.scope, passwords = params.passwords, - start_url = params.start_url, - form = params.form, - html = '', - field, element, fld, i, current_form, - base = $location.path().replace(/^\//, '').split('/')[0], - extra_html = params.extra_html; + callback = params.callback || 'PasswordsAccepted', + password, + form = CredentialForm, + html, + acceptedPasswords = {}, + scope = parent_scope.$new(); - function navigate(canceled) { - //Decide where to send the user once the modal dialog closes - if (!canceled) { - if (base === 'jobs') { - scope.refreshJob(); - } else { - $location.path('/jobs'); - } - } else { - $location.path('/' + base); - } - } + Wait('stop'); + + function promptPassword() { + var e, fld, field; - function cancel() { - // Delete a job - var url = GetBasePath('jobs') + scope.job_id + '/'; - Rest.setUrl(url); - Rest.destroy() - .success(function () { - if (form.name === 'credential') { - navigate(true); - } - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status }); - }); - } - - scope.cancelJob = function () { - // User clicked cancel button - $('#password-modal').modal('hide'); - if (form.name === 'credential') { - cancel(); - } else { - scope.$emit('UpdateSubmitted', 'canceled'); - } - }; - - scope.startJob = function () { - var pswd = {}, value_supplied = false; - $('#password-modal').modal('hide'); - Wait('start'); - $('.password-field').each(function () { - pswd[$(this).attr('name')] = $(this).val(); - if ($(this).val() !== '' && $(this).val() !== null) { - value_supplied = true; - } - }); - if (Empty(passwords) || passwords.length === 0 || value_supplied) { - Rest.setUrl(start_url); - Rest.post(pswd) - .success(function () { - scope.$emit('UpdateSubmitted', 'started'); - if (form.name === 'credential') { - navigate(false); - } - }) - .error(function (data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'POST to ' + start_url + ' failed with status: ' + status }); - }); - } else { - Wait('stop'); - Alert('No Passwords', 'Required password(s) not provided. The request was not submitted.', 'alert-info'); - if (form.name === 'credential') { - // No passwords provided, so we can't start the job. Rather than leave the job in a 'new' - // state, let's delete it. - scope.cancelJob(); - } - } - }; - - if (passwords && passwords.length > 0) { - Wait('stop'); - // Prompt for passwords + password = passwords.pop(); + + // Prompt for password html += "
\n"; - html += (extra_html) ? extra_html : ""; - for (i = 0; i < passwords.length; i++) { - // Add the password field - if (form.name === 'credential') { - // this is a job. we could be prompting for inventory and/or SCM passwords - if (form.fields[passwords[i]]) { - current_form = form; - } - else { - // No match found. Abandon ship! - Alert('Form Not Found', 'Could not locate form for: ' + passwords[i], 'alert-danger'); - $location('/#/jobs'); - } - } else { - current_form = form; - } - field = current_form.fields[passwords[i]]; - fld = passwords[i]; - scope[fld] = ''; - html += "
\n"; - html += "\n"; - html += "
\n"; - html += "A value is required!\n"; - html += "\n"; - html += "
\n"; - html += "
\n"; + field = form.fields[password]; + fld = password; + scope[fld] = ''; + html += "
\n"; + html += "\n"; + html += "
\n"; + html += "A value is required!\n"; + html += "\n"; + html += "
\n"; + html += "
\n"; - // Add the related confirm field + // Add the related confirm field + if (field.associated) { fld = field.associated; - field = current_form.fields[field.associated]; + field = form.fields[field.associated]; scope[fld] = ''; html += "
\n"; - html += "