From 93bd1d859a5665a4c3a507fe2969aba1da6409bf Mon Sep 17 00:00:00 2001 From: Chris Houseknecht Date: Wed, 5 Mar 2014 18:13:49 -0500 Subject: [PATCH] AC-1065 in anticipation of potentially having to sort the keys of any incoming json variable objects, consolidated the variable handling code into a single helper. Anytime variable data is fetched from the API it gets passed to the helper and turned into a YAML doc. The helper checks the incoming data type for string or object. If string it first attempts to parse as YAML. If it fails, then tries JSON. If no joy, fails gracefully, logging the error and notifying the user. Anytime variables need to be sent to the API, a method in the helper is called to parse the variable text into a JSON object. --- awx/ui/static/js/app.js | 3 +- awx/ui/static/js/controllers/JobTemplates.js | 75 +----- awx/ui/static/js/controllers/Jobs.js | 30 +-- awx/ui/static/js/helpers/Groups.js | 229 ++++++------------- awx/ui/static/js/helpers/Hosts.js | 141 ++++-------- awx/ui/static/js/helpers/Variables.js | 109 +++++++++ awx/ui/static/js/helpers/inventory.js | 116 ++++------ awx/ui/templates/ui/index.html | 1 + 8 files changed, 284 insertions(+), 420 deletions(-) create mode 100644 awx/ui/static/js/helpers/Variables.js 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 @@ +