From 1b9c050dc8779bac28d0e05b1dafe4a87ad23add Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Fri, 27 Mar 2015 17:42:04 -0400 Subject: [PATCH 1/7] adding pbrun radio option and input fields --- awx/ui/static/js/forms/Credentials.js | 21 +++++++++++++++++++++ awx/ui/static/js/helpers/Credentials.js | 8 ++++++-- awx/ui/static/js/helpers/JobSubmission.js | 3 +++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index c918b1ae48..9f5bbf7d8b 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -290,6 +290,9 @@ export default }, { label: 'Su', value: 'su' + },{ + label: 'Pbrun', + value: 'pbrun' }], awPopOver: "

Sudo: Optionally specify a username for sudo operations. This is equivalent to specifying the ansible-playbook --sudo-user parameter.
Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.", dataPlacement: 'right', @@ -331,6 +334,24 @@ export default hasShowInputButton: true, autocomplete: false }, + "pbrun_username": { + label: 'Pbrun Username', + type: 'text', + ngShow: "kind.value == 'ssh' && login_method == 'pbrun'", + addRequired: false, + editRequired: false, + autocomplete: false + }, + "pbrun_password": { + label: 'Pbrun Password', + type: 'sensitive', + ngShow: "kind.value == 'ssh' && login_method == 'pbrun'", + addRequired: false, + editRequired: false, + ask: true, + hasShowInputButton: true, + autocomplete: false + }, "project": { label: "Project", type: 'text', diff --git a/awx/ui/static/js/helpers/Credentials.js b/awx/ui/static/js/helpers/Credentials.js index 36abc98ba8..b2160e483b 100644 --- a/awx/ui/static/js/helpers/Credentials.js +++ b/awx/ui/static/js/helpers/Credentials.js @@ -124,10 +124,10 @@ angular.module('CredentialsHelper', ['Utilities']) scope.ssh_key_unlock_confirm = null; scope.sudo_username = null; scope.sudo_password = null; - scope.sudo_password_confirm = null; scope.su_username = null; scope.su_password = null; - scope.su_password_confirm = null; + scope.pbrun_username = null; + scope.pbrun_password = null; } // Collapse or open help widget based on whether scm value is selected @@ -182,6 +182,10 @@ angular.module('CredentialsHelper', ['Utilities']) scope.su_username = null; scope.su_password = null; } + if (login_method !== 'pbrun') { + scope.pbrun_username = null; + scope.pbrun_password = null; + } }; } ]) diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 373814bbf8..f5f3594942 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -850,6 +850,9 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, if(data.su_password === "ASK"){ passwords.push("su_password"); } + if(data.pbrun_password === "ASK"){ + passwords.push("pbrun_password"); + } if(data.vault_password === "ASK"){ passwords.push("vault_password"); } From 4955ad4e0154da6028ce4391a0a5ce4108475d8a Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Mon, 30 Mar 2015 14:15:14 -0400 Subject: [PATCH 2/7] added privilege escalation chxbox to JT form page the job template page will need to have a flag to provide the user to run playbooks as sudo --- awx/ui/static/js/forms/JobTemplates.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index 856c2527bc..a6cb174afe 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -295,6 +295,19 @@ export default // '

A survey is enabled but it does not exist. Create a survey or disable the survey.
' '
A survey is enabled but it does not exist. Create a survey or uncheck the Enable Survey box to disable the survey.
' }, + become: { + label: 'Enable Privilege Escalation', + type: 'checkbox', + addRequired: false, + editRequird: false, + trueValue: 'true', + falseValue: 'false', + column: 2, + awPopOver: "

If enabled, run this playbook as an administrator. This is the equivalent of passing the --become option to the ansible-playbook command.

", + dataPlacement: 'right', + dataTitle: 'Become Privilege Escalation', + dataContainer: "body" + }, allow_callbacks: { label: 'Allow Provisioning Callbacks', type: 'checkbox', From 47d7440b5780b0e832494157954821ce64bd8afb Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 31 Mar 2015 15:45:00 -0400 Subject: [PATCH 3/7] changed credential privilege escalation to selectable --- awx/ui/static/js/forms/Credentials.js | 39 +++++++++++++++------------ 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index 9f5bbf7d8b..a5aa5c13dc 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -275,26 +275,31 @@ export default askShow: "kind.value == 'ssh'", // Only allow ask for machine credentials }, "login_method": { - label: "Privilege Escalation Credentials", + label: "Privilege Escalation Credential", hintText: "If your playbooks use privilege escalation (\"sudo: true\", \"su: true\", etc), you can specify the username to become, and the password to use here.", - type: 'radio_group', + type: 'select', ngShow: "kind.value == 'ssh'", ngChange: "loginMethodChange()", - options: [{ - label: 'None', // FIXME: Maybe 'Default' or 'SSH only' instead? - value: '', - selected: true - }, { - label: 'Sudo', - value: 'sudo' - }, { - label: 'Su', - value: 'su' - },{ - label: 'Pbrun', - value: 'pbrun' - }], - awPopOver: "

Sudo: Optionally specify a username for sudo operations. This is equivalent to specifying the ansible-playbook --sudo-user parameter.
Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.", + ngOptions: 'kind.label for kind in credential_kind_options track by kind.value', + // options: [{ + // label: 'None', // FIXME: Maybe 'Default' or 'SSH only' instead? + // value: '', + // selected: true + // }, { + // label: 'Sudo', + // value: 'sudo' + // }, { + // label: 'Su', + // value: 'su' + // },{ + // label: 'Pbrun', + // value: 'pbrun' + // }], + awPopOver: "

Sudo: Optionally specify a username for sudo operations. "+ + "This is equivalent to specifying the ansible-playbook --sudo-user parameter.
" + + "Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.
"+ + "Pbrun: Optionally specify a username for pbrun operations. This is equivalent to specifying the ansible-playbook --become_method=pbrun parameter."+ + "Note that this option is only available with Tower instances using Ansible v1.9 or later (Current: Ansible v.{{ansible_version}})", dataPlacement: 'right', dataContainer: "body" }, From f6827a1079c6f8745b51dcefe59683133a794ca6 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Thu, 2 Apr 2015 14:58:21 -0400 Subject: [PATCH 4/7] adding options for privilege escalation drop down this will get replaced by info from the back end. --- awx/ui/static/js/controllers/Credentials.js | 23 ++++++- awx/ui/static/js/forms/Credentials.js | 68 +++------------------ 2 files changed, 31 insertions(+), 60 deletions(-) diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js index 600633359d..cb2a355cef 100644 --- a/awx/ui/static/js/controllers/Credentials.js +++ b/awx/ui/static/js/controllers/Credentials.js @@ -158,6 +158,21 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $r variable: 'credential_kind_options' }); + // GetChoices({ + // scope: $scope, + // url: defaultUrl, + // field: 'become', + // variable: 'become_options' + // }); + + $scope.become_options = [ + { value: 'sudo', label: 'Sudo' }, + { value: 'su', label: 'Su' }, + { value: 'pbrun', label: 'Pbrun'}, + { value: 'pfexec', label: 'Pfexec'}, + { value: 'runas', label: 'Runas'} + ]; + LookUpInit({ scope: $scope, form: form, @@ -314,7 +329,13 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ generator.inject(form, { mode: 'edit', related: true, scope: $scope }); generator.reset(); $scope.id = id; - + $scope.become_options = [ + { value: 'sudo', label: 'Sudo' }, + { value: 'su', label: 'Su' }, + { value: 'pbrun', label: 'Pbrun'}, + { value: 'pfexec', label: 'Pfexec'}, + { value: 'runas', label: 'Runas'} + ]; function setAskCheckboxes() { var fld, i; for (fld in form.fields) { diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index a5aa5c13dc..ab5c578b50 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -274,27 +274,13 @@ export default hasShowInputButton: true, askShow: "kind.value == 'ssh'", // Only allow ask for machine credentials }, - "login_method": { - label: "Privilege Escalation Credential", + "become_method": { + label: "Privilege Escalation", hintText: "If your playbooks use privilege escalation (\"sudo: true\", \"su: true\", etc), you can specify the username to become, and the password to use here.", type: 'select', ngShow: "kind.value == 'ssh'", ngChange: "loginMethodChange()", - ngOptions: 'kind.label for kind in credential_kind_options track by kind.value', - // options: [{ - // label: 'None', // FIXME: Maybe 'Default' or 'SSH only' instead? - // value: '', - // selected: true - // }, { - // label: 'Sudo', - // value: 'sudo' - // }, { - // label: 'Su', - // value: 'su' - // },{ - // label: 'Pbrun', - // value: 'pbrun' - // }], + ngOptions: 'become.label for become in become_options track by become.value', awPopOver: "

Sudo: Optionally specify a username for sudo operations. "+ "This is equivalent to specifying the ansible-playbook --sudo-user parameter.
" + "Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.
"+ @@ -303,54 +289,18 @@ export default dataPlacement: 'right', dataContainer: "body" }, - "sudo_username": { - label: 'Sudo Username', + "become_username": { + label: 'Privilege Escalation Username', type: 'text', - ngShow: "kind.value == 'ssh' && login_method == 'sudo'", + ngShow: "kind.value == 'ssh' && become_method", addRequired: false, editRequired: false, autocomplete: false }, - "sudo_password": { - label: 'Sudo Password', + "become_password": { + label: 'Privilege Escalation Password', type: 'sensitive', - ngShow: "kind.value == 'ssh' && login_method == 'sudo'", - addRequired: false, - editRequired: false, - ask: true, - hasShowInputButton: true, - autocomplete: false - }, - "su_username": { - label: 'Su Username', - type: 'text', - ngShow: "kind.value == 'ssh' && login_method == 'su'", - addRequired: false, - editRequired: false, - autocomplete: false - }, - "su_password": { - label: 'Su Password', - type: 'sensitive', - ngShow: "kind.value == 'ssh' && login_method == 'su'", - addRequired: false, - editRequired: false, - ask: true, - hasShowInputButton: true, - autocomplete: false - }, - "pbrun_username": { - label: 'Pbrun Username', - type: 'text', - ngShow: "kind.value == 'ssh' && login_method == 'pbrun'", - addRequired: false, - editRequired: false, - autocomplete: false - }, - "pbrun_password": { - label: 'Pbrun Password', - type: 'sensitive', - ngShow: "kind.value == 'ssh' && login_method == 'pbrun'", + ngShow: "kind.value == 'ssh' && become_method", addRequired: false, editRequired: false, ask: true, From eb5e10aa5ca7ea925e83fc798de2d564670557d4 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 7 Apr 2015 15:11:51 -0400 Subject: [PATCH 5/7] adding 'become' privilege escalation on cred and on job template adding a flag for enabling 'become' escalation. --- awx/ui/static/js/controllers/Credentials.js | 77 ++++++--------------- awx/ui/static/js/forms/Credentials.js | 18 +++-- awx/ui/static/js/forms/JobTemplates.js | 4 +- awx/ui/static/js/helpers/Credentials.js | 33 +-------- awx/ui/static/js/helpers/JobSubmission.js | 10 +-- 5 files changed, 40 insertions(+), 102 deletions(-) diff --git a/awx/ui/static/js/controllers/Credentials.js b/awx/ui/static/js/controllers/Credentials.js index cb2a355cef..dab1960d79 100644 --- a/awx/ui/static/js/controllers/Credentials.js +++ b/awx/ui/static/js/controllers/Credentials.js @@ -136,7 +136,7 @@ CredentialsList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeP export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GenerateList, SearchInit, PaginateInit, LookUpInit, UserList, TeamList, - GetBasePath, GetChoices, Empty, KindChange, OwnerChange, LoginMethodChange, FormSave) { + GetBasePath, GetChoices, Empty, KindChange, OwnerChange, FormSave) { ClearScope(); @@ -158,20 +158,12 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $r variable: 'credential_kind_options' }); - // GetChoices({ - // scope: $scope, - // url: defaultUrl, - // field: 'become', - // variable: 'become_options' - // }); - - $scope.become_options = [ - { value: 'sudo', label: 'Sudo' }, - { value: 'su', label: 'Su' }, - { value: 'pbrun', label: 'Pbrun'}, - { value: 'pfexec', label: 'Pfexec'}, - { value: 'runas', label: 'Runas'} - ]; + GetChoices({ + scope: $scope, + url: defaultUrl, + field: 'become_method', + variable: 'become_options' + }); LookUpInit({ scope: $scope, @@ -224,16 +216,6 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $r OwnerChange({ scope: $scope }); } - if (!Empty($routeParams.su_username) || !Empty($routeParams.su_password)) { - $scope.login_method = 'su'; - LoginMethodChange({ scope: $scope }); - } else if (!Empty($routeParams.sudo_username) || !Empty($routeParams.sudo_password)) { - $scope.login_method = 'sudo'; - LoginMethodChange({ scope: $scope }); - } else { - $scope.login_method = ''; - LoginMethodChange({ scope: $scope }); - } // Handle Kind change $scope.kindChange = function () { @@ -254,11 +236,6 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $r OwnerChange({ scope: $scope }); }; - // Handle Login Method change - $scope.loginMethodChange = function () { - LoginMethodChange({ scope: $scope }); - }; - // Reset defaults $scope.formReset = function () { //DebugForm({ scope: $scope, form: CredentialForm }); @@ -309,13 +286,13 @@ export function CredentialsAdd($scope, $rootScope, $compile, $location, $log, $r CredentialsAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'CredentialForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'generateList', 'SearchInit', 'PaginateInit', - 'LookUpInit', 'UserList', 'TeamList', 'GetBasePath', 'GetChoices', 'Empty', 'KindChange', 'OwnerChange', 'LoginMethodChange', 'FormSave' + 'LookUpInit', 'UserList', 'TeamList', 'GetBasePath', 'GetChoices', 'Empty', 'KindChange', 'OwnerChange', 'FormSave' ]; export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, CredentialForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, Prompt, GetBasePath, GetChoices, - KindChange, UserList, TeamList, LookUpInit, Empty, OwnerChange, LoginMethodChange, FormSave, Stream, Wait) { + KindChange, UserList, TeamList, LookUpInit, Empty, OwnerChange, FormSave, Stream, Wait) { ClearScope(); @@ -329,13 +306,7 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ generator.inject(form, { mode: 'edit', related: true, scope: $scope }); generator.reset(); $scope.id = id; - $scope.become_options = [ - { value: 'sudo', label: 'Sudo' }, - { value: 'su', label: 'Su' }, - { value: 'pbrun', label: 'Pbrun'}, - { value: 'pfexec', label: 'Pfexec'}, - { value: 'runas', label: 'Runas'} - ]; + function setAskCheckboxes() { var fld, i; for (fld in form.fields) { @@ -389,7 +360,6 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ reset: false }); OwnerChange({ scope: $scope }); - LoginMethodChange({ scope: $scope }); Wait('stop'); }); @@ -429,14 +399,13 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ } master.owner = $scope.owner; - if (!Empty($scope.su_username) || !Empty($scope.su_password)) { - $scope.login_method = 'su'; - } else if (!Empty($scope.sudo_username) || !Empty($scope.sudo_password)) { - $scope.login_method = 'sudo'; - } else { - $scope.login_method = ''; + for (i = 0; i < $scope.become_options.length; i++) { + if ($scope.become_options[i].value === data.become_method) { + $scope.become_method = $scope.become_options[i]; + break; + } } - master.login_method = $scope.login_method; + master.become_method = $scope.become_method; for (i = 0; i < $scope.credential_kind_options.length; i++) { if ($scope.credential_kind_options[i].value === data.kind) { @@ -488,6 +457,12 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ callback: 'choicesReadyCredential' }); + GetChoices({ + scope: $scope, + url: defaultUrl, + field: 'become_method', + variable: 'become_options' + }); $scope.showActivity = function () { Stream({ scope: $scope }); }; @@ -506,11 +481,6 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ OwnerChange({ scope: $scope }); }; - // Handle Login Method change - $scope.loginMethodChange = function () { - LoginMethodChange({ scope: $scope }); - }; - // Handle Kind change $scope.kindChange = function () { KindChange({ scope: $scope, form: form, reset: true }); @@ -525,7 +495,6 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ setAskCheckboxes(); KindChange({ scope: $scope, form: form, reset: false }); OwnerChange({ scope: $scope }); - LoginMethodChange({ scope: $scope }); }; // Related set: Add button @@ -615,5 +584,5 @@ export function CredentialsEdit($scope, $rootScope, $compile, $location, $log, $ CredentialsEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'CredentialForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'Prompt', 'GetBasePath', 'GetChoices', 'KindChange', 'UserList', 'TeamList', 'LookUpInit', - 'Empty', 'OwnerChange', 'LoginMethodChange', 'FormSave', 'Stream', 'Wait' + 'Empty', 'OwnerChange', 'FormSave', 'Stream', 'Wait' ]; diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index ab5c578b50..cef7c0ce70 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -276,16 +276,20 @@ export default }, "become_method": { label: "Privilege Escalation", - hintText: "If your playbooks use privilege escalation (\"sudo: true\", \"su: true\", etc), you can specify the username to become, and the password to use here.", + // hintText: "If your playbooks use privilege escalation (\"sudo: true\", \"su: true\", etc), you can specify the username to become, and the password to use here.", type: 'select', ngShow: "kind.value == 'ssh'", - ngChange: "loginMethodChange()", + dataTitle: 'Privilege Escalation', ngOptions: 'become.label for become in become_options track by become.value', - awPopOver: "

Sudo: Optionally specify a username for sudo operations. "+ - "This is equivalent to specifying the ansible-playbook --sudo-user parameter.
" + - "Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.
"+ - "Pbrun: Optionally specify a username for pbrun operations. This is equivalent to specifying the ansible-playbook --become_method=pbrun parameter."+ - "Note that this option is only available with Tower instances using Ansible v1.9 or later (Current: Ansible v.{{ansible_version}})", + awPopOver: "

Specify a username for 'become' operations. " + + "This is equivalent to specifying the --become-method=BECOME_METHOD parameter, where BECOME_METHOD could be "+ + "sudo | su | pbrun | pfexec | runas
(defaults to sudo)

", + + // "

Sudo: Optionally specify a username for sudo operations. "+ + // "This is equivalent to specifying the ansible-playbook --sudo-user parameter.
" + + // "Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.
"+ + // "Pbrun: Optionally specify a username for pbrun operations. This is equivalent to specifying the ansible-playbook --become_method=pbrun parameter."+ + // "Note that this option is only available with Tower instances using Ansible v1.9 or later (Current: Ansible v.{{ansible_version}})", dataPlacement: 'right', dataContainer: "body" }, diff --git a/awx/ui/static/js/forms/JobTemplates.js b/awx/ui/static/js/forms/JobTemplates.js index a6cb174afe..a87c88e5b9 100644 --- a/awx/ui/static/js/forms/JobTemplates.js +++ b/awx/ui/static/js/forms/JobTemplates.js @@ -295,13 +295,11 @@ export default // '

A survey is enabled but it does not exist. Create a survey or disable the survey.
' '
A survey is enabled but it does not exist. Create a survey or uncheck the Enable Survey box to disable the survey.
' }, - become: { + become_enabled: { label: 'Enable Privilege Escalation', type: 'checkbox', addRequired: false, editRequird: false, - trueValue: 'true', - falseValue: 'false', column: 2, awPopOver: "

If enabled, run this playbook as an administrator. This is the equivalent of passing the --become option to the ansible-playbook command.

", dataPlacement: 'right', diff --git a/awx/ui/static/js/helpers/Credentials.js b/awx/ui/static/js/helpers/Credentials.js index b2160e483b..1df3258801 100644 --- a/awx/ui/static/js/helpers/Credentials.js +++ b/awx/ui/static/js/helpers/Credentials.js @@ -122,12 +122,8 @@ angular.module('CredentialsHelper', ['Utilities']) scope.ssh_key_data = null; scope.ssh_key_unlock = null; scope.ssh_key_unlock_confirm = null; - scope.sudo_username = null; - scope.sudo_password = null; - scope.su_username = null; - scope.su_password = null; - scope.pbrun_username = null; - scope.pbrun_password = null; + scope.become_username = null; + scope.become_password = null; } // Collapse or open help widget based on whether scm value is selected @@ -168,29 +164,6 @@ angular.module('CredentialsHelper', ['Utilities']) } ]) - -.factory('LoginMethodChange', [ - function () { - return function (params) { - var scope = params.scope, - login_method = scope.login_method; - if (login_method !== 'sudo') { - scope.sudo_username = null; - scope.sudo_password = null; - } - if (login_method !== 'su') { - scope.su_username = null; - scope.su_password = null; - } - if (login_method !== 'pbrun') { - scope.pbrun_username = null; - scope.pbrun_password = null; - } - }; -} -]) - - .factory('FormSave', ['$location', 'Alert', 'Rest', 'ProcessErrors', 'Empty', 'GetBasePath', 'CredentialForm', 'ReturnToCaller', 'Wait', function ($location, Alert, Rest, ProcessErrors, Empty, GetBasePath, CredentialForm, ReturnToCaller, Wait) { return function (params) { @@ -219,7 +192,7 @@ angular.module('CredentialsHelper', ['Utilities']) } data.kind = scope.kind.value; - + data.become_method = (scope.become_method.value) ? scope.become_method.value : ""; switch (data.kind) { case 'ssh': data.password = scope.ssh_password; diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index f5f3594942..6ed18ef02d 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -844,14 +844,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, if(data.ssh_key_unlock === "ASK"){ passwords.push("ssh_key_unlock"); } - if(data.sudo_password === "ASK"){ - passwords.push("sudo_password"); - } - if(data.su_password === "ASK"){ - passwords.push("su_password"); - } - if(data.pbrun_password === "ASK"){ - passwords.push("pbrun_password"); + if(data.become_password === "ASK"){ + passwords.push("become_password"); } if(data.vault_password === "ASK"){ passwords.push("vault_password"); From d5389cc15dc866e6bea4f6bc2c7768d6875d0a9b Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 7 Apr 2015 16:56:31 -0400 Subject: [PATCH 6/7] refactoring password gathering in job submission --- awx/ui/static/js/helpers/JobSubmission.js | 174 ++++++++-------------- 1 file changed, 61 insertions(+), 113 deletions(-) diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 6ed18ef02d..a13e79825a 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -127,11 +127,11 @@ function(Rest, Wait, ProcessErrors, ToJSON, Empty, GetBasePath) { }]) .factory('PromptForCredential', ['$location', 'Wait', 'GetBasePath', 'LookUpInit', 'JobTemplateForm', 'CredentialList', 'Rest', 'Prompt', 'ProcessErrors', -function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList, Rest, Prompt, ProcessErrors) { + 'CheckPasswords', +function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialList, Rest, Prompt, ProcessErrors, CheckPasswords) { return function(params) { var scope = params.scope, - callback = params.callback || 'CredentialReady', selectionMade; Wait('stop'); @@ -142,7 +142,12 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi } scope.removeShowLookupDialog = scope.$on('ShowLookupDialog', function() { selectionMade = function () { - scope.$emit(callback, scope.credential); + // scope.$emit(callback, scope.credential); + CheckPasswords({ + scope: scope, + credential: scope.credential, + callback: 'ContinueCred' + }); }; LookUpInit({ @@ -345,72 +350,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, html += "\n"; } }); - // html += "\n"; - - // $('#password-modal').empty().html(buildHtml); - // e = angular.element(document.getElementById('password-modal')); - // $compile(e)(scope); scope.$emit(callback, html, url); - // CreateLaunchDialog({scope: scope}) - // buttons = [{ - // label: "Cancel", - // onClick: function() { - // scope.passwordCancel(); - // }, - // icon: "fa-times", - // "class": "btn btn-default", - // "id": "password-cancel-button" - // },{ - // label: "Continue", - // onClick: function() { - // scope.passwordAccept(); - // }, - // icon: "fa-check", - // "class": "btn btn-primary", - // "id": "password-accept-button" - // }]; - - - // CreateDialog({ - // id: 'password-modal', - // scope: scope, - // buttons: buttons, - // width: 600, - // height: (parent_scope.passwords.length > 1) ? 700 : 500, - // minWidth: 500, - // title: 'parent_scope.passwords Required', - // callback: 'DialogReady' - // }); - - // if (scope.removeDialogReady) { - // scope.removeDialogReady(); - // } - // scope.removeDialogReady = scope.$on('DialogReady', function() { - // $('#password-modal').dialog('open'); - // $('#password-accept-button').attr({ "disabled": "disabled" }); - // }); - // scope.keydown = function(e){ - // if(e.keyCode===13){ - // scope.passwordAccept(); - // } - // }; - - // scope.passwordAccept = function() { - // if (!scope.password_form.$invalid) { - // scope.passwords.forEach(function(password) { - // acceptedPasswords[password] = scope[password]; - // }); - // $('#password-modal').dialog('close'); - // scope.$emit(callback, acceptedPasswords); - // } - // }; - - // scope.passwordCancel = function() { - // $('#password-modal').dialog('close'); - // scope.$emit('CancelJob'); - // scope.$destroy(); - // }; // Password change scope.clearPWConfirm = function (fld) { @@ -647,9 +588,6 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, } } - - - Rest.setUrl(survey_url); Rest.get() .success(function (data) { @@ -671,8 +609,45 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, }; }]) + .factory('CheckPasswords', ['$compile', 'Rest', 'GetBasePath', 'TextareaResize', 'CreateLaunchDialog', 'GenerateForm', 'JobVarsPromptForm', 'Wait', + 'ParseVariableString', 'ToJSON', 'ProcessErrors', '$routeParams', 'Empty', + function($compile, Rest, GetBasePath, TextareaResize,CreateLaunchDialog, GenerateForm, JobVarsPromptForm, Wait, + ParseVariableString, ToJSON, ProcessErrors, $routeParams, Empty) { + return function(params) { + var scope = params.scope, + callback = params.callback, + credential = params.credential; + var passwords = []; + if (!Empty(credential)) { + Rest.setUrl(GetBasePath('credentials')+credential); + Rest.get() + .success(function (data) { + if(data.kind === "ssh"){ + if(data.password === "ASK" ){ + passwords.push("ssh_password"); + } + if(data.ssh_key_unlock === "ASK"){ + passwords.push("ssh_key_unlock"); + } + if(data.become_password === "ASK"){ + passwords.push("become_password"); + } + if(data.vault_password === "ASK"){ + passwords.push("vault_password"); + } + scope.$emit(callback, passwords); + } + }) + .error(function (data, status) { + ProcessErrors(scope, data, status, null, { hdr: 'Error!', + msg: 'Failed to get job template details. GET returned status: ' + status }); + }); + } + + }; + }]) /** @@ -828,50 +803,23 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, }); - if (scope.removeCredentialReady) { - scope.removeCredentialReady(); + if (scope.removeContinueCred) { + scope.removeContinueCred(); } - scope.removeCredentialReady = scope.$on('CredentialReady', function(e, credential) { - var passwords = []; - if (!Empty(credential)) { - Rest.setUrl(GetBasePath('credentials')+credential); - Rest.get() - .success(function (data) { - if(data.kind === "ssh"){ - if(data.password === "ASK" ){ - passwords.push("ssh_password"); - } - if(data.ssh_key_unlock === "ASK"){ - passwords.push("ssh_key_unlock"); - } - if(data.become_password === "ASK"){ - passwords.push("become_password"); - } - if(data.vault_password === "ASK"){ - passwords.push("vault_password"); - } - if(passwords.length>0){ - scope.passwords_needed_to_start = passwords; - scope.$emit('PromptForPasswords', passwords, html, url); - } - else if (scope.ask_variables_on_launch){ - scope.$emit('PromptForVars', html, url); - } - else if (!Empty(scope.survey_enabled) && scope.survey_enabled===true) { - scope.$emit('PromptForSurvey', html, url); - } - else { - scope.$emit('StartPlaybookRun', url); - } - } - - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, null, { hdr: 'Error!', - msg: 'Failed to get job template details. GET returned status: ' + status }); - }); - } - + scope.removeContinueCred = scope.$on('ContinueCred', function(e, passwords) { + if(passwords.length>0){ + scope.passwords_needed_to_start = passwords; + scope.$emit('PromptForPasswords', passwords, html, url); + } + else if (scope.ask_variables_on_launch){ + scope.$emit('PromptForVars', html, url); + } + else if (!Empty(scope.survey_enabled) && scope.survey_enabled===true) { + scope.$emit('PromptForSurvey', html, url); + } + else { + scope.$emit('StartPlaybookRun', url); + } }); // Get the job or job_template record From 1d20ddc22749f9fd0fcb24e428f51e08c701a5d6 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 7 Apr 2015 18:14:38 -0400 Subject: [PATCH 7/7] adding comments for job submission --- awx/ui/static/js/forms/Credentials.js | 6 -- awx/ui/static/js/helpers/JobSubmission.js | 74 +++++++++++++++++++++++ 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/awx/ui/static/js/forms/Credentials.js b/awx/ui/static/js/forms/Credentials.js index cef7c0ce70..0bd02f1dcf 100644 --- a/awx/ui/static/js/forms/Credentials.js +++ b/awx/ui/static/js/forms/Credentials.js @@ -284,12 +284,6 @@ export default awPopOver: "

Specify a username for 'become' operations. " + "This is equivalent to specifying the --become-method=BECOME_METHOD parameter, where BECOME_METHOD could be "+ "sudo | su | pbrun | pfexec | runas
(defaults to sudo)

", - - // "

Sudo: Optionally specify a username for sudo operations. "+ - // "This is equivalent to specifying the ansible-playbook --sudo-user parameter.
" + - // "Su: Optionally specify a username for su operations. This is equivalent to specifying the ansible-playbook --su-user parameter.
"+ - // "Pbrun: Optionally specify a username for pbrun operations. This is equivalent to specifying the ansible-playbook --become_method=pbrun parameter."+ - // "Note that this option is only available with Tower instances using Ansible v1.9 or later (Current: Ansible v.{{ansible_version}})", dataPlacement: 'right', dataContainer: "body" }, diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index a13e79825a..b7db81955b 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -8,7 +8,81 @@ * @ngdoc function * @name helpers.function:JobSubmission * @description +* The JobSubmission.js file handles launching a job via a playbook run. There is a workflow that is involved in gathering all the +* variables needed to launch a job, including credentials, passwords, extra variables, and survey data. Depending on what information +* is needed to launch the job, a modal is built that prompts the user for any required information. This modal is built by creating +* an html string with all the fields necessary to launch the job. This html string then gets compiled and opened in a dialog modal. +* +* #Workflow when user hits launch button +* +* A 'get' call is made to the API's 'job_templates/:job_template_id/launch' endpoint for that job template. The response from the API will specify +* +*``` +* "credential_needed_to_start": true, +* "can_start_without_user_input": false, +* "ask_variables_on_launch": false, +* "passwords_needed_to_start": [], +* "variables_needed_to_start": [], +* "survey_enabled": false +*``` +* #Step 1a - Check if there is a credential included in the job template: PromptForCredential +* +* The first step is to check if a credential was specified in the job template, by looking at the value of `credential_needed_to_start` . +* If this boolean is true, then that means that the user did NOT specify a credential in the job template and we must prompt them to select a credential. +* This emits a call to `PromptForCredential` which will do a lookup on the credentials endpoint and show a modal window with the list +* of credentials for the user to choose from. +* +* #Step 1b - Check if the credential requires a password: CheckPasswords +* +* The second part of this process is to check if the credential the user picks requires a prompt for a password. A call is made (in the `CheckPasswords` factory) +* to the chosen credential +* and checks if ``password: ASK`` , ``become_password:ASK`` , or ``vault_password: ASK``. If any of these are ASK, then we begin building the html string for +* each required password (see step 2). If none of these require a password, then we contine on to prompting for vars (see step 3) +* +* #Step 2 - Build password html string: PromptForPasswords +* +* We may detect from the inital 'get' call that we may need to prompt the user for passwords. The ``passwords_needed_to_start`` array from the 'get' call +* will explictly tell us which passwords we must prompt for. Alternatively, we may have found that in steps 1a and 1b that +* we have must prompt for passwords. Either way, we arrive in `PromptForPasswords` factory which builds the html string depending on how the particular credential is setup. +* +* #Step 3 - extra vars text editor: PromptForVars +* +* We may arrive at step three if the credential selected does not require a password, or if the password html string is already done being built. +* if ``ask_variables_on_launch`` was true in the inital 'get' call, then we build the extra_vars text editor in the `PromptForVars` factory. +* This factory makes a REST call to the job template and finds if any 'extra_vars' were specified in the job template. It takes any specified +* extra vars and includes them in the extra_vars text editor that is built in the same factory. This code is added to the html string and passed along +* to the next step. +* +* #Step 4 - Survey Taker: PromptForSurvey +* +* The last step in building the job submission modal is building the survey taker. If ``survey_enabled`` is true from the initial 'get' call, +* we make a REST call to the survey endpoint for the specified job and gather the survey data. The `PromptForSurvey` factory takes the survey +* data and adds to the html string any various survey question. +* +* #Step 5 - build the modal: CreateLaunchDialog +* +* At this point, we need to compile our giant html string onto the modal and open the job submission modal. This happens in the `CreateLaunch` +* factory. In this factory the 'Launch' button for the job is tied to the validity of the form, which handles the validation of these fields. +* +* #Step 6 - Launch the job: LaunchJob +* +* This is maybe the most crucial step. We have setup everything we need in order to gather information from the user and now we want to be sure +* we handle it correctly. And there are many scenarios to take into account. The first scenario we check for is is ``survey_enabled=true`` and +* ``prompt_for_vars=false``, in which case we want to make sure to include the extra_vars from the job template in the data being +* sent to the API (it is important to note that anything specified in the extra vars on job submission will override vars specified in the job template. +* Likewise, any variables specified in the extra vars that are duplicated by the survey vars, will get overridden by the survey vars). +* If the previous scenario is NOT the case, then we continue to gather the modal's answers regularly: gather the passwords, then the extra_vars, then +* any survey results. Also note that we must gather any required survey answers, as well as any optional survey answers that happened to be provided +* by the user. We also include the credential that was chosen if the user was prompted to select a credential. +* At this point we have all the info we need and we are almost ready to perform a POST to the '/launch' endpoint. We must lastly check +* if the user was not prompted for anything and therefore we don't want to pass any extra_vars to the POST. Once this is done we +* make the REST POST call and provide all the data to hte API. The response from the API will be the job ID, which is used to redirect the user +* to the job detail page for that job run. +* +* @Usage +* This is usage information. */ + 'use strict'; export default