From 7ecde597acc32e89058031b90ad1d96bb1fd3263 Mon Sep 17 00:00:00 2001 From: Cristian Vargas Date: Wed, 20 Jun 2018 22:42:18 -0500 Subject: [PATCH 1/7] Make LAST UPDATED field in projects table sortable Signed-off-by: Cristian Vargas --- awx/ui/client/src/projects/projects.list.js | 1 - 1 file changed, 1 deletion(-) diff --git a/awx/ui/client/src/projects/projects.list.js b/awx/ui/client/src/projects/projects.list.js index 06fcd7d1d4..53d4aefce3 100644 --- a/awx/ui/client/src/projects/projects.list.js +++ b/awx/ui/client/src/projects/projects.list.js @@ -57,7 +57,6 @@ export default ['i18n', function(i18n) { filter: "longDate", columnClass: "col-lg-3 hidden-md hidden-sm hidden-xs", excludeModal: true, - nosort: true } }, From 475a2bd9bb9165b0557b9bb3ec714bf6353b467f Mon Sep 17 00:00:00 2001 From: Cristian Vargas Date: Thu, 21 Jun 2018 11:53:33 -0500 Subject: [PATCH 2/7] Remove trailing comma Signed-off-by: Cristian Vargas --- awx/ui/client/src/projects/projects.list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/projects/projects.list.js b/awx/ui/client/src/projects/projects.list.js index 53d4aefce3..86547c8b66 100644 --- a/awx/ui/client/src/projects/projects.list.js +++ b/awx/ui/client/src/projects/projects.list.js @@ -56,7 +56,7 @@ export default ['i18n', function(i18n) { label: i18n._('Last Updated'), filter: "longDate", columnClass: "col-lg-3 hidden-md hidden-sm hidden-xs", - excludeModal: true, + excludeModal: true } }, From 4b7f106e9f4ad7fbaef875b2e191b0e8f3c9ced8 Mon Sep 17 00:00:00 2001 From: Paul Neumann Date: Mon, 14 May 2018 21:53:27 +0200 Subject: [PATCH 3/7] Enable source variables for Azure inventory --- awx/main/tasks.py | 5 ++++ .../sources/add/sources-add.controller.js | 2 +- .../sources/edit/sources-edit.controller.js | 2 +- .../related/sources/sources.form.js | 24 +++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index cb6c3c76af..c22c0f0cbe 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1946,12 +1946,17 @@ class RunInventoryUpdate(BaseTask): cp.set(section, 'group_by_resource_group', 'yes') cp.set(section, 'group_by_location', 'yes') cp.set(section, 'group_by_tag', 'yes') + if inventory_update.source_regions and 'all' not in inventory_update.source_regions: cp.set( section, 'locations', ','.join([x.strip() for x in inventory_update.source_regions.split(',')]) ) + azure_rm_opts = dict(inventory_update.source_vars_dict.items()) + for k,v in azure_rm_opts.items(): + cp.set(section, k, six.text_type(v)) + # Return INI content. if cp.sections(): f = cStringIO.StringIO() diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js index 4415dc386d..f1515a81c9 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/add/sources-add.controller.js @@ -164,7 +164,7 @@ export default ['$state', '$stateParams', '$scope', 'SourcesFormDefinition', else{ $scope.credentialBasePath = (source === 'ec2') ? GetBasePath('credentials') + '?kind=aws' : GetBasePath('credentials') + (source === '' ? '' : '?kind=' + (source)); } - if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm' || source === 'cloudforms' || source === "satellite6") { + if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm' || source === 'cloudforms' || source === "satellite6" || source === "azure_rm") { $scope.envParseType = 'yaml'; var varName; diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js index eb3c083cd4..6f3997fea0 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/edit/sources-edit.controller.js @@ -66,7 +66,7 @@ export default ['$state', '$stateParams', '$scope', 'ParseVariableString', if (source === 'ec2' || source === 'custom' || source === 'vmware' || source === 'openstack' || source === 'scm' || source === 'cloudforms' || - source === 'satellite6') { + source === 'satellite6' || source === 'azure_rm') { var varName; if (source === 'scm') { diff --git a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js index bffc91e3d0..ec554a5225 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js +++ b/awx/ui/client/src/inventories-hosts/inventories/related/sources/sources.form.js @@ -303,6 +303,30 @@ return { dataContainer: 'body', subForm: 'sourceSubForm' }, + azure_rm_variables: { + id: 'azure_rm_variables', + label: i18n._('Source Variables'), //"{{vars_label}}" , + ngShow: "source && source.value == 'azure_rm'", + type: 'textarea', + class: 'Form-textAreaLabel Form-formGroup--fullWidth', + rows: 6, + 'default': '---', + parseTypeName: 'envParseType', + dataTitle: i18n._("Source Variables"), + dataPlacement: 'right', + awPopOver: "

" + i18n._("Override variables found in azure_rm.ini and used by the inventory update script. For a detailed description of these variables ") + + "" + + i18n._("view azure_rm.ini in the Ansible github repo.") + "

" + + "

" + i18n._("Enter variables using either JSON or YAML syntax. Use the radio button to toggle between the two.") + "

" + + i18n._("JSON:") + "
\n" + + "
{
 \"somevar\": \"somevalue\",
 \"password\": \"magic\"
}
\n" + + i18n._("YAML:") + "
\n" + + "
---
somevar: somevalue
password: magic
\n" + + "

" + i18n._("View JSON examples at ") + 'www.json.org

' + + "

" + i18n._("View YAML examples at ") + 'docs.ansible.com

', + dataContainer: 'body', + subForm: 'sourceSubForm' + }, verbosity: { label: i18n._('Verbosity'), type: 'select', From 73197f3ae5ec14005c6eb49b710a2e835177f2c3 Mon Sep 17 00:00:00 2001 From: Paul Neumann Date: Sat, 23 Jun 2018 19:02:15 +0200 Subject: [PATCH 4/7] Extend unit test for Azure source variable generation Add tests for generation of Azure source variables. Test cases such as overwriting a variable with its default value, overwriting a variable with something different to its default value and add variables not set by default. --- awx/main/tests/unit/test_tasks.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index c94c205b86..05eb6393d1 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1890,6 +1890,10 @@ class TestInventoryUpdateCredentials(TestJobExecution): ) return cred self.instance.get_cloud_credential = get_cred + self.instance.source_vars = { + 'include_powerstate': 'yes', + 'group_by_resource_group': 'no' + } def run_pexpect_side_effect(*args, **kwargs): args, cwd, env, stdout = args @@ -1902,8 +1906,9 @@ class TestInventoryUpdateCredentials(TestJobExecution): config = ConfigParser.ConfigParser() config.read(env['AZURE_INI_PATH']) assert config.get('azure', 'include_powerstate') == 'yes' - assert config.get('azure', 'group_by_resource_group') == 'yes' + assert config.get('azure', 'group_by_resource_group') == 'no' assert config.get('azure', 'group_by_location') == 'yes' + assert 'group_by_security_group' not in config.items('azure') assert config.get('azure', 'group_by_tag') == 'yes' assert config.get('azure', 'locations') == 'north,south,east,west' return ['successful', 0] @@ -1930,6 +1935,11 @@ class TestInventoryUpdateCredentials(TestJobExecution): ) return cred self.instance.get_cloud_credential = get_cred + self.instance.source_vars = { + 'include_powerstate': 'yes', + 'group_by_resource_group': 'no', + 'group_by_security_group': 'no' + } def run_pexpect_side_effect(*args, **kwargs): args, cwd, env, stdout = args @@ -1941,8 +1951,9 @@ class TestInventoryUpdateCredentials(TestJobExecution): config = ConfigParser.ConfigParser() config.read(env['AZURE_INI_PATH']) assert config.get('azure', 'include_powerstate') == 'yes' - assert config.get('azure', 'group_by_resource_group') == 'yes' + assert config.get('azure', 'group_by_resource_group') == 'no' assert config.get('azure', 'group_by_location') == 'yes' + assert config.get('azure', 'group_by_security_group') == 'no' assert config.get('azure', 'group_by_tag') == 'yes' assert 'locations' not in config.items('azure') return ['successful', 0] From 14def1e693c1b743de53ff1d05bf887a27198313 Mon Sep 17 00:00:00 2001 From: moss Date: Tue, 22 May 2018 23:32:54 +0300 Subject: [PATCH 5/7] add want_hostcollections for sat6 source vars Signed-off-by: moss --- awx/main/tasks.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index c22c0f0cbe..ffb646856a 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1889,6 +1889,7 @@ class RunInventoryUpdate(BaseTask): group_patterns = '[]' group_prefix = 'foreman_' + want_hostcollections = 'False' foreman_opts = dict(inventory_update.source_vars_dict.items()) foreman_opts.setdefault('ssl_verify', 'False') for k, v in foreman_opts.items(): @@ -1896,6 +1897,8 @@ class RunInventoryUpdate(BaseTask): group_patterns = v elif k == 'satellite6_group_prefix' and isinstance(v, basestring): group_prefix = v + elif k == 'satellite6_want_hostcollections' and isinstance(v, bool): + want_hostcollections = v else: cp.set(section, k, six.text_type(v)) @@ -1908,6 +1911,7 @@ class RunInventoryUpdate(BaseTask): cp.add_section(section) cp.set(section, 'group_patterns', group_patterns) cp.set(section, 'want_facts', True) + cp.set(section, 'want_hostcollections', want_hostcollections) cp.set(section, 'group_prefix', group_prefix) section = 'cache' From ae4135f149b569a2e650cc77dfe0e566485d12fd Mon Sep 17 00:00:00 2001 From: Bill Nottingham Date: Mon, 9 Jul 2018 11:49:45 -0400 Subject: [PATCH 6/7] add tests --- awx/main/tests/unit/test_tasks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 05eb6393d1..830c3577fd 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -2066,7 +2066,7 @@ class TestInventoryUpdateCredentials(TestJobExecution): return cred self.instance.get_cloud_credential = get_cred - self.instance.source_vars = '{"satellite6_group_patterns": "[a,b,c]", "satellite6_group_prefix": "hey_"}' + self.instance.source_vars = '{"satellite6_group_patterns": "[a,b,c]", "satellite6_group_prefix": "hey_", "satellite6_want_hostcollections": True}' def run_pexpect_side_effect(*args, **kwargs): args, cwd, env, stdout = args @@ -2077,6 +2077,7 @@ class TestInventoryUpdateCredentials(TestJobExecution): assert config.get('foreman', 'password') == 'secret' assert config.get('ansible', 'group_patterns') == '[a,b,c]' assert config.get('ansible', 'group_prefix') == 'hey_' + assert config.get('ansible', 'want_hostcollections') == 'True' return ['successful', 0] self.run_pexpect.side_effect = run_pexpect_side_effect From 6378479ee7739b12c7a2f828ceac10758826015b Mon Sep 17 00:00:00 2001 From: Rob Ruma Date: Wed, 21 Mar 2018 08:22:08 -0400 Subject: [PATCH 7/7] Updates to callback scripts that include retry functionality for bash and extra_vars handling for PowerShell Signed-off-by: Rob Ruma --- tools/scripts/request_tower_configuration.ps1 | 29 ++++-- tools/scripts/request_tower_configuration.sh | 93 +++++++++++-------- 2 files changed, 73 insertions(+), 49 deletions(-) diff --git a/tools/scripts/request_tower_configuration.ps1 b/tools/scripts/request_tower_configuration.ps1 index 17f1e91012..db18bfa6bd 100644 --- a/tools/scripts/request_tower_configuration.ps1 +++ b/tools/scripts/request_tower_configuration.ps1 @@ -1,7 +1,8 @@ Param( [string]$tower_url, [string]$host_config_key, - [string]$job_template_id + [string]$job_template_id, + [string]$extra_vars ) Set-StrictMode -Version 2 @@ -10,24 +11,36 @@ $ErrorActionPreference = "Stop" If(-not $tower_url -or -not $host_config_key -or -not $job_template_id) { Write-Host "Requests server configuration from Ansible Tower" - Write-Host "Usage: $($MyInvocation.MyCommand.Name) [:server port] " - Write-Host "Example: $($MyInvocation.MyCommand.Name) example.towerhost.net 44d7507f2ead49af5fca80aa18fd24bc 38" + Write-Host "Usage: $($MyInvocation.MyCommand.Name) https://[:server port] " + Write-Host "Example: $($MyInvocation.MyCommand.Name) https://example.towerhost.net 44d7507f2ead49af5fca80aa18fd24bc 38" + Write-Host "Example with extra_vars: $($MyInvocation.MyCommand.Name) https://example.towerhost.net 44d7507f2ead49af5fca80aa18fd24bc 38 '{ key: value, dict: { key: value }}'" Exit 1 } $retry_attempts = 10 $attempt = 0 -$data = @{ - host_config_key=$host_config_key +If(-not $extra_vars) +{ + $data = @{ + host_config_key=$host_config_key + } +} Else { + $data = @{ + host_config_key=$host_config_key + extra_vars=$extra_vars + } } While ($attempt -lt $retry_attempts) { Try { - $resp = Invoke-WebRequest -Method POST -Body $data -Uri http://$tower_url/api/v1/job_templates/$job_template_id/callback/ -UseBasicParsing + $resp = Invoke-WebRequest -ContentType application/json -Method POST -Body (ConvertTo-Json $data) -Uri $tower_url/api/v2/job_templates/$job_template_id/callback/ - If($resp.StatusCode -eq 202) { + If ($resp.StatusCode -match '^2[0-9]+$') { Exit 0 + } ElseIf ($resp.StatusCode -eq 404) { + Write-Host "$resp.StatusCode received... encountered problem, halting" + Exit 1 } } Catch { @@ -37,4 +50,4 @@ While ($attempt -lt $retry_attempts) { } Start-Sleep -Seconds 60 } -Exit 1 \ No newline at end of file +Exit 1 diff --git a/tools/scripts/request_tower_configuration.sh b/tools/scripts/request_tower_configuration.sh index 05d75a69dd..1c0718ef49 100755 --- a/tools/scripts/request_tower_configuration.sh +++ b/tools/scripts/request_tower_configuration.sh @@ -1,10 +1,10 @@ #!/bin/bash fatal() { - if [ -n "${2}" ]; then - echo -e "Error: ${2}" - fi - exit ${1} + if [ -n "${2}" ]; then + echo -e "Error: ${2}" + fi + exit ${1} } usage() { @@ -29,31 +29,31 @@ INSECURE="" # Parse arguments while getopts “hks:c:t:s:e:” OPTION do - case ${OPTION} in - h) - usage - exit 1 - ;; - s) - TOWER_SERVER=${OPTARG} - ;; - k) - INSECURE="-k" - ;; - c) - HOST_CFG_KEY=${OPTARG} - ;; - t) - TEMPLATE_ID=${OPTARG} - ;; - e) - EXTRA_VARS=${OPTARG} - ;; - ?) - usage - exit - ;; - esac + case ${OPTION} in + h) + usage + exit 1 + ;; + s) + TOWER_SERVER=${OPTARG} + ;; + k) + INSECURE="-k" + ;; + c) + HOST_CFG_KEY=${OPTARG} + ;; + t) + TEMPLATE_ID=${OPTARG} + ;; + e) + EXTRA_VARS=${OPTARG} + ;; + ?) + usage + exit + ;; + esac done # Validate required arguments @@ -65,21 +65,32 @@ test -z ${TEMPLATE_ID} && fatal 1 "Missing required -t argument" # Generate curl --data parameter if [ -n "${EXTRA_VARS}" ]; then - CURL_DATA="{\"host_config_key\": \"${HOST_CFG_KEY}\", \"extra_vars\": \"${EXTRA_VARS}\"}" + CURL_DATA="{\"host_config_key\": \"${HOST_CFG_KEY}\", \"extra_vars\": \"${EXTRA_VARS}\"}" else - CURL_DATA="{\"host_config_key\": \"${HOST_CFG_KEY}\"}" + CURL_DATA="{\"host_config_key\": \"${HOST_CFG_KEY}\"}" fi -set -o pipefail -HTTP_STATUS=$(curl ${INSECURE} -s -i -X POST -H 'Content-Type:application/json' --data "$CURL_DATA" ${TOWER_SERVER}/api/v1/job_templates/${TEMPLATE_ID}/callback/ 2>&1 | head -n1 | awk '{print $2}') -CURL_RC=$? -if [ ${CURL_RC} -ne 0 ]; then +# Success on any 2xx status received, failure on only 404 status received, retry any other status every min for up to 10 min +RETRY_ATTEMPTS=10 +ATTEMPT=0 +while [[ $ATTEMPT -lt $RETRY_ATTEMPTS ]] +do + set -o pipefail + HTTP_STATUS=$(curl ${INSECURE} -s -i -X POST -H 'Content-Type:application/json' --data "$CURL_DATA" ${TOWER_SERVER}/api/v2/job_templates/${TEMPLATE_ID}/callback/ 2>&1 | head -n1 | awk '{print $2}') + CURL_RC=$? + if [ ${CURL_RC} -ne 0 ]; then fatal ${CURL_RC} "curl exited with ${CURL_RC}, halting." -fi + fi -# Extract http status code -if [[ ${HTTP_STATUS} -ge 300 ]]; then - fatal 1 "${HTTP_STATUS} received, encountered problem, halting." -else + # Extract http status code + if [[ ${HTTP_STATUS} =~ ^2[0-9]+$ ]]; then echo "Success: ${HTTP_STATUS} received." -fi + break + elif [[ ${HTTP_STATUS} =~ ^404$ ]]; then + fatal 1 "Failed: ${HTTP_STATUS} received, encountered problem, halting." + else + ATTEMPT=$((ATTEMPT + 1)) + echo "Failed: ${HTTP_STATUS} received, executing retry #${ATTEMPT} in 1 minute." + sleep 60 + fi +done