diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index 22e3455789..d3a09f6013 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -85,7 +85,8 @@ angular.module('ansible', [ 'StreamListDefinition', 'HomeGroupListDefinition', 'HomeHostListDefinition', - 'ActivityDetailDefinition' + 'ActivityDetailDefinition', + 'VariablesHelper' ]) .config(['$routeProvider', function ($routeProvider) { diff --git a/awx/ui/static/js/controllers/JobTemplates.js b/awx/ui/static/js/controllers/JobTemplates.js index 147a8bcbd9..4a684d5276 100644 --- a/awx/ui/static/js/controllers/JobTemplates.js +++ b/awx/ui/static/js/controllers/JobTemplates.js @@ -108,7 +108,7 @@ JobTemplatesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$route function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, ReturnToCaller, ClearScope, GetBasePath, - InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange, Wait, Empty) { + InventoryList, CredentialList, ProjectList, LookUpInit, md5Setup, ParseTypeChange, Wait, Empty, ToJSON) { ClearScope(); @@ -286,20 +286,8 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa $scope.formSave = function () { generator.clearApiErrors(); Wait('start'); - var data = {}, json_data, fld; + var data = {}, fld; try { - // Make sure we have valid variable data - if ($scope.parseType === 'json') { - json_data = JSON.parse($scope.variables); //make sure JSON parses - } else { - json_data = jsyaml.load($scope.variables); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - for (fld in form.fields) { if (form.fields[fld].type === 'select' && fld !== 'playbook') { data[fld] = $scope[fld].value; @@ -309,11 +297,7 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa } } } - - data.extra_vars = JSON.stringify(json_data, undefined, '\t'); - if (Empty(data.extra_vars)) { - data.extra_vars = ""; - } + data.extra_vars = ToJSON($scope.parseType, $scope.variables, true); Rest.setUrl(defaultUrl); Rest.post(data) @@ -346,14 +330,14 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa JobTemplatesAdd.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'ReturnToCaller', 'ClearScope', 'GetBasePath', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', - 'md5Setup', 'ParseTypeChange', 'Wait', 'Empty' + 'md5Setup', 'ParseTypeChange', 'Wait', 'Empty', 'ToJSON' ]; function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm, GenerateForm, Rest, Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList, CredentialList, ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, ParseTypeChange, JobStatusToolTip, FormatDate, - Wait, Stream, Empty, Prompt) { + Wait, Stream, Empty, Prompt, ParseVariableString, ToJSON) { ClearScope(); @@ -569,7 +553,7 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP Rest.setUrl(defaultUrl + ':id/'); Rest.get({ params: { id: id } }) .success(function (data) { - var fld, i, json_obj, related, set; + var fld, i, related, set; LoadBreadCrumbs({ path: '/job_templates/' + id, title: data.name }); for (fld in form.fields) { if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) { @@ -589,28 +573,8 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP master[fld] = $scope[fld]; } if (fld === 'variables') { - // Parse extra_vars, converting to YAML. - if ($.isEmptyObject(data.extra_vars) || data.extra_vars === "{}" || data.extra_vars === "null" || - data.extra_vars === "" || data.extra_vars === null) { - $scope.variables = "---"; - } else { - $scope.variables = '---'; - try { - json_obj = JSON.parse(data.extra_vars); - $scope.variables = jsyaml.safeDump(json_obj); - } - catch (e) { - $log.info('Attempt to parse extra_vars as JSON faild. Attempting to parse as YAML'); - try { - json_obj = jsyaml.safeLoad(data.extra_vars); - $scope.variables = jsyaml.safeDump(json_obj); - } - catch(e2) { - ProcessErrors($scope, data.extra_vars, e2.message, null, { hdr: 'Error!', - msg: 'Attempts to parse variables as JSON and YAML failed. Last attempt returned: ' + e2.message }); - } - } - } + // Parse extra_vars, converting to YAML. + $scope.variables = ParseVariableString(data.extra_vars); master.variables = $scope.variables; } if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) { @@ -702,20 +666,10 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP $scope.formSave = function () { generator.clearApiErrors(); Wait('start'); - var data = {}, json_data, fld; + var data = {}, fld; try { // Make sure we have valid variable data - if ($scope.parseType === 'json') { - json_data = JSON.parse($scope.variables); //make sure JSON parses - } else { - json_data = jsyaml.load($scope.variables); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - + data.extra_vars = ToJSON($scope.parseType, $scope.variables, true); for (fld in form.fields) { if (form.fields[fld].type === 'select' && fld !== 'playbook') { data[fld] = $scope[fld].value; @@ -725,12 +679,6 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP } } } - - data.extra_vars = JSON.stringify(json_data, undefined, '\t'); - if (data.extra_vars === "null" || data.extra_vars === null) { - data.extra_vars = ""; - } - Rest.setUrl(defaultUrl + id + '/'); Rest.put(data) .success(function (data) { @@ -810,5 +758,6 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP JobTemplatesEdit.$inject = ['$scope', '$rootScope', '$compile', '$location', '$log', '$routeParams', 'JobTemplateForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LoadBreadCrumbs', 'RelatedSearchInit', 'RelatedPaginateInit', 'ReturnToCaller', 'ClearScope', 'InventoryList', 'CredentialList', 'ProjectList', 'LookUpInit', 'PromptPasswords', - 'GetBasePath', 'md5Setup', 'ParseTypeChange', 'JobStatusToolTip', 'FormatDate', 'Wait', 'Stream', 'Empty', 'Prompt' + 'GetBasePath', 'md5Setup', 'ParseTypeChange', 'JobStatusToolTip', 'FormatDate', 'Wait', 'Stream', 'Empty', 'Prompt', + 'ParseVariableString', 'ToJSON' ]; \ No newline at end of file diff --git a/awx/ui/static/js/controllers/Jobs.js b/awx/ui/static/js/controllers/Jobs.js index 2f71835c75..4aa2c3c2c7 100644 --- a/awx/ui/static/js/controllers/Jobs.js +++ b/awx/ui/static/js/controllers/Jobs.js @@ -8,8 +8,6 @@ * */ -/* global jsyaml:false */ - 'use strict'; function JobsListCtrl($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobList, GenerateList, LoadBreadCrumbs, Prompt, @@ -189,7 +187,8 @@ JobsListCtrl.$inject = ['$scope', '$rootScope', '$location', '$log', '$routePara 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) { + CredentialList, ProjectList, LookUpInit, PromptPasswords, GetBasePath, md5Setup, FormatDate, JobStatusToolTip, Wait, Empty, + ParseVariableString) { ClearScope(); @@ -374,28 +373,7 @@ function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, J } } if (fld === 'variables') { - // Parse extra_vars, converting to YAML. - if ($.isEmptyObject(data.extra_vars) || data.extra_vars === "{}" || data.extra_vars === "null" || - data.extra_vars === "" || data.extra_vars === null) { - $scope.variables = "---"; - } else { - $scope.variables = '---'; - try { - json_obj = JSON.parse(data.extra_vars); - $scope.variables = jsyaml.safeDump(json_obj); - } - catch (e) { - $log.info('Attempt to parse extra_vars as JSON faild. Attempting to parse as YAML'); - try { - json_obj = jsyaml.safeLoad(data.extra_vars); - $scope.variables = jsyaml.safeDump(json_obj); - } - catch(e2) { - ProcessErrors($scope, data.extra_vars, e2.message, null, { hdr: 'Error!', - msg: 'Attempts to parse variables as JSON and YAML failed. Last attempt returned: ' + e2.message }); - } - } - } + $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] = @@ -446,5 +424,5 @@ function JobsEdit($scope, $rootScope, $compile, $location, $log, $routeParams, J 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' + 'GetBasePath', 'md5Setup', 'FormatDate', 'JobStatusToolTip', 'Wait', 'Empty', 'ParseVariableString' ]; diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 8a3526974d..3684935e31 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -12,8 +12,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'GroupListDefinition', 'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'AuthService', 'GroupsHelper', 'InventoryHelper', 'SelectionHelper', 'JobSubmissionHelper', 'RefreshHelper', 'PromptDialog', 'CredentialsListDefinition', 'InventoryTree', - 'InventoryStatusDefinition' -]) + 'InventoryStatusDefinition', 'VariablesHelper']) .factory('GetSourceTypeOptions', ['Rest', 'ProcessErrors', 'GetBasePath', function (Rest, ProcessErrors, GetBasePath) { @@ -322,10 +321,10 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G .factory('GroupsAdd', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'ParseTypeChange', 'Wait', 'GetChoices', - 'GetSourceTypeOptions', 'LookUpInit', 'BuildTree', 'SourceChange', 'WatchInventoryWindowResize', + 'GetSourceTypeOptions', 'LookUpInit', 'BuildTree', 'SourceChange', 'WatchInventoryWindowResize', 'ToJSON', function ($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, GetBasePath, ParseTypeChange, Wait, GetChoices, GetSourceTypeOptions, LookUpInit, BuildTree, - SourceChange, WatchInventoryWindowResize) { + SourceChange, WatchInventoryWindowResize, ToJSON) { return function (params) { var inventory_id = params.inventory_id, @@ -403,8 +402,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G var parseError = false, data = {}, - regions, r, i, - json_data; + regions, r, i; // Update the selector tree with new group name, descr //SetNodeName({ scope: scope['selectedNode'], group_id: group_id, @@ -428,30 +426,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G data.source_regions = r.join(); if (scope.source.value === 'ec2') { - // for ec2, validate variable data - try { - if (scope.envParseType === 'json') { - json_data = JSON.parse(scope.source_vars); //make sure JSON parses - } else { - json_data = jsyaml.load(scope.source_vars); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - // Send JSON as a string - if ($.isEmptyObject(json_data)) { - data.source_vars = ""; - } else { - data.source_vars = JSON.stringify(json_data, undefined, '\t'); - } - } catch (err) { - parseError = true; - scope.$emit('SaveComplete', true); - Alert("Error", "Error parsing extra variables. Parser returned: " + err); - } + data.source_vars = ToJSON(scope.envParseType, scope.source_vars, true); } if (!parseError) { @@ -484,54 +459,28 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G // Save scope.formModalAction = function () { - var json_data, data; + var data; Wait('start'); - try { - scope.formModalActionDisabled = true; - - // Make sure we have valid variable data - if (scope.parseType === 'json') { - json_data = JSON.parse(scope.variables); //make sure JSON parses - } else { - json_data = jsyaml.load(scope.variables); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - data = { - name: scope.name, - description: scope.description - }; - - if (inventory_id) { - data.inventory = inventory_id; - } - - if ($.isEmptyObject(json_data)) { - data.variables = ""; - } else { - data.variables = JSON.stringify(json_data, undefined, '\t'); - } - - Rest.setUrl(defaultUrl); - Rest.post(data) - .success(function (data) { - scope.$emit('formSaveSuccess', data.id, GetBasePath('inventory_sources') + data.id + '/'); - }) - .error(function (data, status) { - Wait('stop'); - scope.formModalActionDisabled = false; - ProcessErrors(scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to add new group. POST returned status: ' + status }); - }); - } catch (err) { - Wait('stop'); - scope.formModalActionDisabled = false; - Alert("Error", "Error parsing group variables. Parser returned: " + err); + scope.formModalActionDisabled = true; + data = { + name: scope.name, + description: scope.description + }; + if (inventory_id) { + data.inventory = inventory_id; } + data.variables = ToJSON(scope.parseType, scope.variables, true); + Rest.setUrl(defaultUrl); + Rest.post(data) + .success(function (data) { + scope.$emit('formSaveSuccess', data.id, GetBasePath('inventory_sources') + data.id + '/'); + }) + .error(function (data, status) { + Wait('stop'); + scope.formModalActionDisabled = false; + ProcessErrors(scope, data, status, form, { hdr: 'Error!', + msg: 'Failed to add new group. POST returned status: ' + status }); + }); }; scope.sourceChange = function () { @@ -584,9 +533,12 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G .factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate', 'LookUpInit', 'Empty', 'Wait', 'GetChoices', 'UpdateGroup', 'SourceChange', 'Find','WatchInventoryWindowResize', + 'ParseVariableString', 'ToJSON', function ($rootScope, $location, $log, $routeParams, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, LookUpInit, Empty, Wait, - GetChoices, UpdateGroup, SourceChange, Find, WatchInventoryWindowResize) { + GetChoices, UpdateGroup, SourceChange, Find, WatchInventoryWindowResize, + ParseVariableString, ToJSON) { + return function (params) { var parent_scope = params.scope, @@ -647,11 +599,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G Rest.setUrl(scope.variable_url); Rest.get() .success(function (data) { - if ($.isEmptyObject(data)) { - scope.variables = "---"; - } else { - scope.variables = jsyaml.safeDump(data); - } + scope.variables = ParseVariableString(data); scope.$emit('groupVariablesLoaded'); }) .error(function (data, status) { @@ -670,7 +618,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G Rest.setUrl(scope.source_url); Rest.get() .success(function (data) { - var fld, i, j, flag, found, json_obj, set, opts, list; + var fld, i, j, flag, found, set, opts, list; for (fld in form.fields) { if (fld === 'checkbox_group') { for (i = 0; i < form.fields[fld].fields.length; i++) { @@ -706,13 +654,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G } } else if (fld === 'source_vars') { // Parse source_vars, converting to YAML. - if ($.isEmptyObject(data.source_vars) || data.source_vars === "{}" || - data.source_vars === "null" || data.source_vars === "") { - scope.source_vars = "---"; - } else { - json_obj = JSON.parse(data.source_vars); - scope.source_vars = jsyaml.safeDump(json_obj); - } + scope.source_vars = ParseVariableString(data.source_vars); master.source_vars = scope.variables; } else if (data[fld]) { scope[fld] = data[fld]; @@ -882,7 +824,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G // related fields, then call SaveComplete to wrap things up. var parseError = false, - regions, r, i, json_data, + regions, r, i, data = { group: group_id, source: ((scope.source && scope.source.value) ? scope.source.value : ''), @@ -903,29 +845,7 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G if (scope.source && scope.source.value === 'ec2') { // for ec2, validate variable data - try { - if (scope.envParseType === 'json') { - json_data = JSON.parse(scope.source_vars); //make sure JSON parses - } else { - json_data = jsyaml.load(scope.source_vars); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - // Send JSON as a string - if ($.isEmptyObject(json_data)) { - data.source_vars = ""; - } else { - data.source_vars = JSON.stringify(json_data); - } - } catch (err) { - parseError = true; - scope.$emit('SaveComplete', true); - Alert("Error", "Error parsing extra variables. Parser returned: " + err); - } + data.source_vars = ToJSON(scope.envParseType, scope.source_vars, true); } if (!parseError) { @@ -953,57 +873,42 @@ angular.module('GroupsHelper', ['RestServices', 'Utilities', 'ListGenerator', 'G // Save scope.formModalAction = function () { Wait('start'); - try { - var fld, data, json_data; + var fld, data, json_data; - // Make sure we have valid variable data - if (scope.parseType === 'json') { - json_data = JSON.parse(scope.variables); //make sure JSON parses - } else { - json_data = jsyaml.load(scope.variables); //parse yaml - } + json_data = ToJSON(scope.parseType, scope.variables); - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - data = {}; - for (fld in form.fields) { - data[fld] = scope[fld]; - } - - data.inventory = inventory_id; - - Rest.setUrl(defaultUrl); - Rest.put(data) - .success(function () { - if (scope.variables) { - //update group variables - Rest.setUrl(scope.variable_url); - Rest.put(json_data) - .success(function () { - scope.$emit('formSaveSuccess'); - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to update group variables. PUT status: ' + status }); - }); - } else { - scope.$emit('formSaveSuccess'); - } - }) - .error(function (data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, form, { - hdr: 'Error!', - msg: 'Failed to update group: ' + group_id + '. PUT status: ' + status - }); - }); - } catch (err) { - Wait('stop'); - Alert("Error", "Error parsing group variables. Parser returned: " + err); + data = {}; + for (fld in form.fields) { + data[fld] = scope[fld]; } + + data.inventory = inventory_id; + + Rest.setUrl(defaultUrl); + Rest.put(data) + .success(function () { + if (scope.variables) { + //update group variables + Rest.setUrl(scope.variable_url); + Rest.put(json_data) + .success(function () { + scope.$emit('formSaveSuccess'); + }) + .error(function (data, status) { + ProcessErrors(scope, data, status, form, { hdr: 'Error!', + msg: 'Failed to update group variables. PUT status: ' + status }); + }); + } else { + scope.$emit('formSaveSuccess'); + } + }) + .error(function (data, status) { + Wait('stop'); + ProcessErrors(scope, data, status, form, { + hdr: 'Error!', + msg: 'Failed to update group: ' + group_id + '. PUT status: ' + status + }); + }); }; // Start the update process diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index 9cbf93eee1..2489dee95e 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -14,7 +14,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', 'HostListDefinition', 'SearchHelper', 'PaginationHelpers', 'ListGenerator', 'AuthService', 'HostsHelper', 'InventoryHelper', 'RelatedSearchHelper', 'InventoryFormDefinition', 'SelectionHelper', - 'HostGroupsFormDefinition' + 'HostGroupsFormDefinition', 'VariablesHelper' ]) .factory('SetEnabledMsg', [ function() { @@ -320,8 +320,9 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostList, Gener .factory('HostsCreate', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'WatchInventoryWindowResize', + 'ToJSON', function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, HostsReload, ParseTypeChange, Wait, WatchInventoryWindowResize) { + GetBasePath, HostsReload, ParseTypeChange, Wait, WatchInventoryWindowResize, ToJSON) { return function(params) { var parent_scope = params.scope, @@ -380,55 +381,27 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener Wait('start'); - try { - var fld, json_data, data={}; - scope.formModalActionDisabled = true; - - // Make sure we have valid variable data - if (scope.parseType === 'json') { - json_data = JSON.parse(scope.variables); //make sure JSON parses + var fld, data={}; + scope.formModalActionDisabled = true; + data.variables = ToJSON(scope.parseType, scope.variables, true); + for (fld in form.fields) { + if (fld !== 'variables') { + data[fld] = scope[fld]; } - else { - json_data = jsyaml.load(scope.variables); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - for (fld in form.fields) { - if (fld !== 'variables') { - data[fld] = scope[fld]; - } - } - - data.inventory = inventory_id; - - if ($.isEmptyObject(json_data)) { - data.variables = ""; - } - else { - data.variables = JSON.stringify(json_data, undefined, '\t'); - } - - Rest.setUrl(defaultUrl); - Rest.post(data) - .success( function() { - scope.$emit('HostSaveComplete'); - }) - .error( function(data, status) { - Wait('stop'); - scope.formModalActionDisabled = false; - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to add new host. POST returned status: ' + status }); - }); - } - catch(err) { - Wait('stop'); - scope.formModalActionDisabled = false; - Alert("Error", "Error parsing host variables. Parser returned: " + err); } + data.inventory = inventory_id; + + Rest.setUrl(defaultUrl); + Rest.post(data) + .success( function() { + scope.$emit('HostSaveComplete'); + }) + .error( function(data, status) { + Wait('stop'); + scope.formModalActionDisabled = false; + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to add new host. POST returned status: ' + status }); + }); }; // Cancel @@ -447,9 +420,10 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener .factory('HostsEdit', ['$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'HostForm', 'GenerateForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'HostsReload', 'ParseTypeChange', 'Wait', 'Find', 'SetStatus', 'ApplyEllipsis', - 'WatchInventoryWindowResize', + 'WatchInventoryWindowResize', 'ToJSON', 'ParseVariableString', function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, GenerateForm, Prompt, ProcessErrors, - GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetStatus, ApplyEllipsis, WatchInventoryWindowResize) { + GetBasePath, HostsReload, ParseTypeChange, Wait, Find, SetStatus, ApplyEllipsis, WatchInventoryWindowResize, ToJSON, + ParseVariableString) { return function(params) { var parent_scope = params.scope, @@ -486,12 +460,7 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener Rest.setUrl(scope.variable_url); Rest.get() .success( function(data) { - if ($.isEmptyObject(data)) { - scope.variables = "---"; - } - else { - scope.variables = jsyaml.safeDump(data); - } + scope.variables = ParseVariableString(data); scope.$emit('hostVariablesLoaded'); }) .error( function(data, status) { @@ -570,49 +539,23 @@ function($rootScope, $location, $log, $routeParams, Rest, Alert, HostForm, Gener scope.formModalAction = function() { Wait('start'); - - try { - // Make sure we have valid variable data - var fld, json_data, data={}; - if (scope.parseType === 'json') { - json_data = JSON.parse(scope.variables); //make sure JSON parses - } - else { - json_data = jsyaml.load(scope.variables); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - for (fld in form.fields) { - data[fld] = scope[fld]; - } - data.inventory = inventory_id; - - if ($.isEmptyObject(json_data)) { - data.variables = ""; - } - else { - data.variables = JSON.stringify(json_data, undefined, '\t'); - } - - Rest.setUrl(defaultUrl); - Rest.put(data) - .success( function() { - scope.$emit('saveCompleted'); - }) - .error( function(data, status) { - Wait('stop'); - ProcessErrors(scope, data, status, form, - { hdr: 'Error!', msg: 'Failed to update host: ' + host_id + '. PUT returned status: ' + status }); - }); - } - catch(err) { - Wait('stop'); - Alert("Error", "Error parsing host variables. Parser returned: " + err); + var fld, data={}; + + data.variables = ToJSON(scope.parseType, scope.variables, true); + for (fld in form.fields) { + data[fld] = scope[fld]; } + data.inventory = inventory_id; + Rest.setUrl(defaultUrl); + Rest.put(data) + .success( function() { + scope.$emit('saveCompleted'); + }) + .error( function(data, status) { + Wait('stop'); + ProcessErrors(scope, data, status, form, + { hdr: 'Error!', msg: 'Failed to update host: ' + host_id + '. PUT returned status: ' + status }); + }); }; // Cancel diff --git a/awx/ui/static/js/helpers/Variables.js b/awx/ui/static/js/helpers/Variables.js new file mode 100644 index 0000000000..31e3bd7cc5 --- /dev/null +++ b/awx/ui/static/js/helpers/Variables.js @@ -0,0 +1,109 @@ +/********************************************* + * Copyright (c) 2014 AnsibleWorks, Inc. + * + * VariablesHelper + * + * Show the CodeMirror variable editor and allow + * toggle between JSON and YAML + * + */ + +'use strict'; + +angular.module('VariablesHelper', ['Utilities']) + + /** + variables: string containing YAML or JSON | a JSON object. + + If JSON string, convert to JSON object and run through jsyaml.safeDump() to create a YAML document. If YAML, + will attempt to load via jsyaml.safeLoad() and return a YAML document using jsyaml.safeDump(). In all cases + a YAML document is returned. + **/ + .factory('ParseVariableString', ['$log', 'ProcessErrors', function ($log, ProcessErrors) { + return function (variables) { + var result = "---", json_obj; + if (typeof variables === 'string') { + if ($.isEmptyObject(variables) || variables === "{}" || variables === "null" || + variables === "" || variables === null) { + // String is empty, return --- + } else { + try { + json_obj = JSON.parse(variables); + result = jsyaml.safeDump(json_obj); + } + catch (e) { + $log.info('Attempt to parse extra_vars as JSON faild. Attempting to parse as YAML'); + try { + json_obj = jsyaml.safeLoad(variables); + result = jsyaml.safeDump(json_obj); + } + catch(e2) { + ProcessErrors(null, variables, e2.message, null, { hdr: 'Error!', + msg: 'Attempts to parse variables as JSON and YAML failed. Last attempt returned: ' + e2.message }); + } + } + } + } + else { + // an object was passed in. just convert to yaml + try { + result = jsyaml.safeDump(variables); + } + catch(e3) { + ProcessErrors(null, variables, e3.message, null, { hdr: 'Error!', + msg: 'Attempt to convert JSON object to YAML document failed: ' + e3.message }); + } + } + return result; + }; + }]) + + /** + parseType: 'json' | 'yaml' + variables: string containing JSON or YAML + stringify: optional, boolean + + Parse the given string according to the parseType to a JSON object. If stringify true, + stringify the object and return the string. Otherwise, return the JSON object. + + **/ + .factory('ToJSON', ['$log', 'ProcessErrors', function($log, ProcessErrors) { + return function(parseType, variables, stringify) { + var json_data, result; + if (parseType === 'json') { + try { + json_data = JSON.parse(variables); //make sure JSON parses + } + catch(e) { + json_data = {}; + $log.error('Failed to parse JSON string. Parser returned: ' + e.message); + ProcessErrors(null, variables, e.message, null, { hdr: 'Error!', + msg: 'Failed to parse JSON string. Parser returned: ' + e.message }); + } + } else { + try { + json_data = jsyaml.load(variables); + } + catch(e) { + json_data = {}; + $log.error('Failed to parse YAML string. Parser returned: ' + e.message); + ProcessErrors(null, variables, e.message, null, { hdr: 'Error!', + msg: 'Failed to parse YAML string. Parser returned: ' + e.message }); + } + } + // Make sure our JSON is actually an object + if (typeof json_data !== 'object') { + ProcessErrors(null, variables, null, null, { hdr: 'Error!', + msg: 'Failed to parse variables. Attempted to parse ' + parseType + ' Parser did not return an object.' }); + } + result = json_data; + if (stringify) { + if ($.isEmptyObject(json_data)) { + result = ""; + } else { + result = JSON.stringify(json_data, undefined, '\t'); + } + } + return result; + }; + }]); \ No newline at end of file diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index 0a9f618a55..b060f1e756 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -11,7 +11,7 @@ 'use strict'; angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationListDefinition', 'ListGenerator', 'AuthService', - 'InventoryHelper', 'InventoryFormDefinition', 'ParseHelper', 'SearchHelper' + 'InventoryHelper', 'InventoryFormDefinition', 'ParseHelper', 'SearchHelper', 'VariablesHelper', ]) .factory('WatchInventoryWindowResize', ['ApplyEllipsis', @@ -40,8 +40,9 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis ]) .factory('SaveInventory', ['InventoryForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList', - 'GetBasePath', 'ParseTypeChange', 'Wait', - function (InventoryForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, Wait) { + 'GetBasePath', 'ParseTypeChange', 'Wait', 'ToJSON', + function (InventoryForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, Wait, + ToJSON) { return function (params) { // Save inventory property modifications @@ -52,67 +53,58 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis fld, json_data, data; Wait('start'); + + // Make sure we have valid variable data + json_data = ToJSON(scope.inventoryParseType, scope.inventory_variables); + + // Make sure our JSON is actually an object + if (typeof json_data !== 'object') { + throw "failed to return an object!"; + } - try { - // Make sure we have valid variable data - if (scope.inventoryParseType === 'json') { - json_data = JSON.parse(scope.inventory_variables); //make sure JSON parses - } else { - json_data = jsyaml.load(scope.inventory_variables); //parse yaml - } - - // Make sure our JSON is actually an object - if (typeof json_data !== 'object') { - throw "failed to return an object!"; - } - - data = {}; - for (fld in form.fields) { - if (fld !== 'inventory_variables') { - if (form.fields[fld].realName) { - data[form.fields[fld].realName] = scope[fld]; - } else { - data[fld] = scope[fld]; - } + data = {}; + for (fld in form.fields) { + if (fld !== 'inventory_variables') { + if (form.fields[fld].realName) { + data[form.fields[fld].realName] = scope[fld]; + } else { + data[fld] = scope[fld]; } } - - Rest.setUrl(defaultUrl + scope.inventory_id + '/'); - Rest.put(data) - .success(function (data) { - if (scope.inventory_variables) { - Rest.setUrl(data.related.variable_data); - Rest.put(json_data) - .success(function () { - Wait('stop'); - scope.$emit('InventorySaved'); - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to update inventory varaibles. PUT returned status: ' + status - }); - }); - } else { - scope.$emit('InventorySaved'); - } - }) - .error(function (data, status) { - ProcessErrors(scope, data, status, form, { hdr: 'Error!', - msg: 'Failed to update inventory. POST returned status: ' + status }); - }); - } catch (err) { - Wait('stop'); - Alert("Error", "Error parsing inventory variables. Parser returned: " + err); } + + Rest.setUrl(defaultUrl + scope.inventory_id + '/'); + Rest.put(data) + .success(function (data) { + if (scope.inventory_variables) { + Rest.setUrl(data.related.variable_data); + Rest.put(json_data) + .success(function () { + Wait('stop'); + scope.$emit('InventorySaved'); + }) + .error(function (data, status) { + ProcessErrors(scope, data, status, form, { hdr: 'Error!', + msg: 'Failed to update inventory varaibles. PUT returned status: ' + status + }); + }); + } else { + scope.$emit('InventorySaved'); + } + }) + .error(function (data, status) { + ProcessErrors(scope, data, status, form, { hdr: 'Error!', + msg: 'Failed to update inventory. POST returned status: ' + status }); + }); }; } ]) .factory('EditInventoryProperties', ['InventoryForm', 'GenerateForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList', - 'GetBasePath', 'ParseTypeChange', 'SaveInventory', 'Wait', 'Store', 'SearchInit', + 'GetBasePath', 'ParseTypeChange', 'SaveInventory', 'Wait', 'Store', 'SearchInit', 'ParseVariableString', function (InventoryForm, GenerateForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, SaveInventory, - Wait, Store, SearchInit) { + Wait, Store, SearchInit, ParseVariableString) { return function (params) { var parent_scope = params.scope, @@ -146,23 +138,10 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis Rest.setUrl(GetBasePath('inventory') + inventory_id + '/'); Rest.get() .success(function (data) { - var fld, json_obj; + var fld; for (fld in form.fields) { if (fld === 'inventory_variables') { - // Parse variables, converting to YAML. - if ($.isEmptyObject(data.variables) || data.variables === "{}" || - data.variables === "null" || data.variables === "") { - scope.inventory_variables = "---"; - } else { - try { - json_obj = JSON.parse(data.variables); - scope.inventory_variables = jsyaml.safeDump(json_obj); - } catch (err) { - Alert('Variable Parse Error', 'Attempted to parse variables for inventory: ' + inventory_id + - '. Parse returned: ' + err); - scope.inventory_variables = '---'; - } - } + scope.inventory_variables = ParseVariableString(data.variables); master.inventory_variables = scope.variables; } else if (fld === 'inventory_name') { scope[fld] = data.name; @@ -174,7 +153,6 @@ angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationLis scope[fld] = data[fld]; master[fld] = scope[fld]; } - if (form.fields[fld].sourceModel && data.summary_fields && data.summary_fields[form.fields[fld].sourceModel]) { scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] = diff --git a/awx/ui/templates/ui/index.html b/awx/ui/templates/ui/index.html index 1a634e1611..b1498e1e52 100644 --- a/awx/ui/templates/ui/index.html +++ b/awx/ui/templates/ui/index.html @@ -127,6 +127,7 @@ +