From a41077df2076f5c41c99207bda45ec5b2fbd7208 Mon Sep 17 00:00:00 2001 From: Jordan Borean Date: Thu, 28 Sep 2017 16:15:55 +1000 Subject: [PATCH] fix for webapppool when specifying an attribute that holds a collection (#30729) * fix for webapppool when specifying an attribute that holds a collection * re-add always block on test --- .../modules/windows/win_iis_webapppool.ps1 | 93 +++++++++++++++++-- .../modules/windows/win_iis_webapppool.py | 1 + .../win_iis_webapppool/tasks/tests.yml | 54 +++++++++++ 3 files changed, 139 insertions(+), 9 deletions(-) diff --git a/lib/ansible/modules/windows/win_iis_webapppool.ps1 b/lib/ansible/modules/windows/win_iis_webapppool.ps1 index c61c81be2ae..5f579297515 100644 --- a/lib/ansible/modules/windows/win_iis_webapppool.ps1 +++ b/lib/ansible/modules/windows/win_iis_webapppool.ps1 @@ -72,6 +72,54 @@ Function Get-DotNetClassForAttribute($attribute_parent) { } } +Function Convert-CollectionToList($collection) { + $list = @() + + if ($collection -is [String]) { + $raw_list = $collection -split "," + foreach ($entry in $raw_list) { + $list += $entry.Trim() + } + } elseif ($collection -is [Microsoft.IIs.PowerShell.Framework.ConfigurationElement]) { + # the collection is the value from IIS itself, we need to conver accordingly + foreach ($entry in $collection.Collection) { + $list += $entry.Value.ToString() + } + } elseif ($collection -isnot [Array]) { + $list += $collection + } else { + $list = $collection + } + + return ,$list +} + +Function Compare-Values($current, $new) { + if ($current -eq $null) { + return $true + } + + if ($current -is [Array]) { + if ($new -isnot [Array]) { + return $true + } + + if ($current.Count -ne $new.Count) { + return $true + } + for ($i = 0; $i -lt $current.Count; $i++) { + if ($current[$i] -ne $new[$i]) { + return $true + } + } + } else { + if ($current -ne $new) { + return $true + } + } + return $false +} + Function Convert-ToPropertyValue($pool, $attribute_key, $attribute_value) { # Will convert the new value to the enum value expected and cast accordingly to the type if ([bool]($attribute_value.PSobject.Properties -match "Value")) { @@ -82,13 +130,25 @@ Function Convert-ToPropertyValue($pool, $attribute_key, $attribute_value) { $attribute_parent = "attributes" $attribute_child = $attribute_key $attribute_meta = $pool.Attributes | Where-Object { $_.Name -eq $attribute_child } - } elseif ($attribute_key_split.Length -eq 2) { + } elseif ($attribute_key_split.Length -gt 1) { $attribute_parent = $attribute_key_split[0] - $attribute_child = $attribute_key_split[1] - $attribute_meta = $pool.$attribute_parent.Attributes | Where-Object { $_.Name -eq $attribute_child } + $attribute_key_split = $attribute_key_split[1..$($attribute_key_split.Length - 1)] + $parent = $pool.$attribute_parent + + foreach ($key in $attribute_key_split) { + $attribute_meta = $parent.Attributes | Where-Object { $_.Name -eq $key } + $parent = $parent.$key + if ($attribute_meta -eq $null) { + $attribute_meta = $parent + } + } + $attribute_child = $attribute_key_split[-1] } if ($attribute_meta) { + if (($attribute_meta.PSObject.Properties.Name -eq "Collection").Count -gt 0) { + return ,(Convert-CollectionToList -collection $attribute_value) + } $type = $attribute_meta.Schema.Type $value = $attribute_value if ($type -eq "enum") { @@ -169,12 +229,27 @@ if ($state -eq "absent") { $current_raw_value = Get-ItemProperty -Path IIS:\AppPools\$name -Name $attribute_key -ErrorAction SilentlyContinue $current_value = Convert-ToPropertyValue -pool $pool -attribute_key $attribute_key -attribute_value $current_raw_value - # Cannot use ($current_value -or (..)) as that will fire if $current_value is 0/$null/"" when we only want $null - if (($current_value -eq $null) -or ($current_value -ne $new_value)) { - try { - Set-ItemProperty -Path IIS:\AppPools\$name -Name $attribute_key -Value $new_value -WhatIf:$check_mode - } catch { - Fail-Json $result "Failed to set attribute to Web App Pool $name. Attribute: $attribute_key, Value: $new_value, Exception: $($_.Exception.Message)" + $changed = Compare-Values -current $current_value -new $new_value + if ($changed -eq $true) { + if ($new_value -is [Array]) { + try { + Clear-ItemProperty -Path IIS:\AppPools\$name -Name $attribute_key -WhatIf:$check_mode + } catch { + Fail-Json -obj $result -message "Failed to clear attribute to Web App Pool $name. Attribute: $attribute_key, Exception: $($_.Exception.Message)" + } + foreach ($value in $new_value) { + try { + New-ItemProperty -Path IIS:\AppPools\$name -Name $attribute_key -Value @{value=$value} -WhatIf:$check_mode + } catch { + Fail-Json -obj $result -message "Failed to add new attribute to Web App Pool $name. Attribute: $attribute_key, Value: $value, Exception: $($_.Exception.Message)" + } + } + } else { + try { + Set-ItemProperty -Path IIS:\AppPools\$name -Name $attribute_key -Value $new_value -WhatIf:$check_mode + } catch { + Fail-Json $result "Failed to set attribute to Web App Pool $name. Attribute: $attribute_key, Value: $new_value, Exception: $($_.Exception.Message)" + } } $result.changed = $true } diff --git a/lib/ansible/modules/windows/win_iis_webapppool.py b/lib/ansible/modules/windows/win_iis_webapppool.py index 0c28f5091ba..6da8ccbad29 100644 --- a/lib/ansible/modules/windows/win_iis_webapppool.py +++ b/lib/ansible/modules/windows/win_iis_webapppool.py @@ -144,6 +144,7 @@ EXAMPLES = r''' attributes: # Timespan with full string "day:hour:minute:second.millisecond" recycling.periodicRestart.time: "00:00:05:00.000000" + recycling.periodicRestart.schedule: ["00:10:00", "05:30:00"] # Shortened timespan "hour:minute:second" processModel.pingResponseTime: "00:03:00" ''' diff --git a/test/integration/targets/win_iis_webapppool/tasks/tests.yml b/test/integration/targets/win_iis_webapppool/tasks/tests.yml index a7929803616..ab34d043c9d 100644 --- a/test/integration/targets/win_iis_webapppool/tasks/tests.yml +++ b/test/integration/targets/win_iis_webapppool/tasks/tests.yml @@ -343,6 +343,60 @@ - restart_from_stop_pool|changed - restart_from_stop_pool_actual.stdout == 'Started\r\n' +- name: set web pool attribute that is a collection (check mode) + win_iis_webapppool: + name: '{{test_iis_webapppool_name}}' + state: present + attributes: + recycling.periodicRestart.schedule: "00:10:00,10:10:00" + register: collection_change_check + check_mode: yes + +- name: get result of set web pool attribute that is a collection (check mode) + win_shell: | + Import-Module WebAdministration + (Get-ItemProperty -Path "IIS:\AppPools\{{test_iis_webapppool_name}}" -Name recycling.periodicRestart.schedule).Collection | ForEach-Object { $_.value.ToString() } + register: collection_change_result_check + +- name: assert results of set web pool attribute that is a collection (check mode) + assert: + that: + - collection_change_check|changed + - collection_change_result_check.stdout == "" + +- name: set web pool attribute that is a collection + win_iis_webapppool: + name: '{{test_iis_webapppool_name}}' + state: present + attributes: + recycling.periodicRestart.schedule: "00:10:00,10:10:00" + register: collection_change + +- name: get result of set web pool attribute that is a collection + win_shell: | + Import-Module WebAdministration + (Get-ItemProperty -Path "IIS:\AppPools\{{test_iis_webapppool_name}}" -Name recycling.periodicRestart.schedule).Collection | ForEach-Object { $_.value.ToString() } + register: collection_change_result + +- name: assert results of set web pool attribute that is a collection + assert: + that: + - collection_change|changed + - collection_change_result.stdout_lines == [ "00:10:00", "10:10:00" ] + +- name: set web pool attribute that is a collection (idempotent) + win_iis_webapppool: + name: '{{test_iis_webapppool_name}}' + state: present + attributes: + recycling.periodicRestart.schedule: [ "00:10:00", "10:10:00" ] + register: collection_change_again + +- name: assert results of set web pool attribute that is a collection (idempotent) + assert: + that: + - not collection_change_again|changed + # The following tests are only for IIS versions 8.0 or newer - block: - name: delete test pool