win_dsc: improved parameter handling (#31556)
* win_dsc: improved parameter handling * removed uneeded try/catch leftover from testing * removed undeed return values * added custom DSC to fully test out casting * fix up codestyle issues * using new Requires ps version check * fixed up error message check on earlier ps version
This commit is contained in:
parent
55bc8291d6
commit
978a979566
14 changed files with 1127 additions and 313 deletions
|
@ -1,75 +1,169 @@
|
|||
#!powershell
|
||||
# (c) 2015, Trond Hindenes <trond@hindenes.com>, and others
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# WANT_JSON
|
||||
# POWERSHELL_COMMON
|
||||
# (c) 2015, Trond Hindenes <trond@hindenes.com>, and others
|
||||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#Temporary fix
|
||||
#Set-StrictMode -Off
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
#Requires -Version 5
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$params = Parse-Args $args -supports_check_mode $true
|
||||
$result = @{
|
||||
changed = $false
|
||||
}
|
||||
|
||||
#Check that we're on at least Powershell version 5
|
||||
if ($PSVersionTable.PSVersion.Major -lt 5)
|
||||
Function ConvertTo-HashtableFromPsCustomObject($psObject)
|
||||
{
|
||||
Fail-Json -obj $Result -message "This module only runs on Powershell version 5 or higher"
|
||||
$hashtable = @{}
|
||||
$psObject | Get-Member -MemberType *Property | ForEach-Object {
|
||||
$value = $psObject.($_.Name)
|
||||
if ($value -is [PSObject])
|
||||
{
|
||||
$value = ConvertTo-HashtableFromPsCustomObject -myPsObject $value
|
||||
}
|
||||
$hashtable.($_.Name) = $value
|
||||
}
|
||||
|
||||
return ,$hashtable
|
||||
}
|
||||
|
||||
Function Cast-ToCimInstance($name, $value, $className)
|
||||
{
|
||||
# this converts a hashtable to a CimInstance
|
||||
if ($value -is [PSObject])
|
||||
{
|
||||
# convert to hashtable
|
||||
$value = ConvertTo-HashtableFromPsCustomObject -psObject $value
|
||||
}
|
||||
|
||||
$valueType = $value.GetType()
|
||||
if ($valueType -ne [hashtable])
|
||||
{
|
||||
Fail-Json -obj $result -message "CimInstance value for property $name must be a hashtable, was $($valueType.FullName)"
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$cim = New-CimInstance -ClassName $className -Property $value -ClientOnly
|
||||
}
|
||||
catch
|
||||
{
|
||||
Fail-Json -obj $result -message "Failed to convert hashtable to CimInstance of $($className): $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
return ,$cim
|
||||
}
|
||||
|
||||
Function Cast-Value($value, $type, $typeString, $name)
|
||||
{
|
||||
if ($type -eq [CimInstance])
|
||||
{
|
||||
$newValue = Cast-ToCimInstance -name $name -value $value -className $typeString
|
||||
}
|
||||
ElseIf ($type -eq [CimInstance[]])
|
||||
{
|
||||
if ($value -isnot [array])
|
||||
{
|
||||
$value = @($value)
|
||||
}
|
||||
[CimInstance[]]$newValue = @()
|
||||
$baseTypeString = $typeString.Substring(0, $typeString.Length - 2)
|
||||
foreach ($cim in $value)
|
||||
{
|
||||
$newValue += Cast-ToCimInstance -name $name -value $cim -className $baseTypeString
|
||||
}
|
||||
}
|
||||
Else
|
||||
{
|
||||
$originalType = $value.GetType()
|
||||
if ($originalType -eq $type)
|
||||
{
|
||||
$newValue = $value
|
||||
}
|
||||
Else
|
||||
{
|
||||
$newValue = $value -as $type
|
||||
if ($newValue -eq $null)
|
||||
{
|
||||
Add-Warning -obj $result -message "failed to cast property $name from '$value' of type $($originalType.FullName) to type $($type.FullName), the DSC engine may ignore this property with an invalid cast"
|
||||
$newValue = $value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ,$newValue
|
||||
}
|
||||
|
||||
Function Parse-DscProperty($name, $value, $resourceProp)
|
||||
{
|
||||
$propertyTypeString = $resourceProp.PropertyType
|
||||
if ($propertyTypeString.StartsWith("["))
|
||||
{
|
||||
$propertyTypeString = $propertyTypeString.Substring(1, $propertyTypeString.Length - 2)
|
||||
}
|
||||
$propertyType = $propertyTypeString -as [type]
|
||||
|
||||
# CimInstance and CimInstance[] are reperesented as the actual Cim
|
||||
# ClassName and the above returns a $null. We need to manually set the
|
||||
# type in these cases
|
||||
if ($propertyType -eq $null)
|
||||
{
|
||||
if ($propertyTypeString.EndsWith("[]"))
|
||||
{
|
||||
$propertyType = [CimInstance[]]
|
||||
}
|
||||
Else
|
||||
{
|
||||
$propertyType = [CimInstance]
|
||||
}
|
||||
}
|
||||
|
||||
if ($propertyType.IsArray)
|
||||
{
|
||||
# convert the value to a list for later conversion
|
||||
if ($value -is [string])
|
||||
{
|
||||
$value = $value.Split(",").Trim()
|
||||
}
|
||||
ElseIf ($value -isnot [array])
|
||||
{
|
||||
$value = @($value)
|
||||
}
|
||||
}
|
||||
$newValue = Cast-Value -value $value -type $propertyType -typeString $propertyTypeString -name $name
|
||||
|
||||
return ,$newValue
|
||||
}
|
||||
|
||||
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
|
||||
$resourcename = Get-AnsibleParam -obj $params -name "resource_name" -type "str" -failifempty $true -resultobj $result
|
||||
$resourcename = Get-AnsibleParam -obj $params -name "resource_name" -type "str" -failifempty $true
|
||||
$module_version = Get-AnsibleParam -obj $params -name "module_version" -type "str" -default "latest"
|
||||
|
||||
#From Ansible 2.3 onwards, params is now a Hash Array
|
||||
$Attributes = $params.GetEnumerator() |
|
||||
Where-Object {
|
||||
$_.key -ne "resource_name" -and
|
||||
$_.key -ne "module_version" -and
|
||||
$_.key -notlike "_ansible_*"
|
||||
$Attributes = @{}
|
||||
foreach ($param in $params.GetEnumerator())
|
||||
{
|
||||
if ($param.Name -notin @("resource_name", "module_version") -and $param.Name -notlike "_ansible_*")
|
||||
{
|
||||
$Attributes[$param.Name] = $param.Value
|
||||
}
|
||||
}
|
||||
|
||||
if (!($Attributes))
|
||||
if ($Attributes.Count -eq 0)
|
||||
{
|
||||
Fail-Json -obj $result -message "No attributes specified"
|
||||
}
|
||||
|
||||
#Always return some basic info
|
||||
$result["resource_name"] = $resourcename
|
||||
$result["attributes"] = $Attributes
|
||||
$result["reboot_required"] = $null
|
||||
|
||||
|
||||
# Build Attributes Hashtable for DSC Resource Propertys
|
||||
$Attrib = @{}
|
||||
foreach ($key in $Attributes)
|
||||
{
|
||||
$result[$key.name] = $key.value
|
||||
$Attrib.Add($Key.Key,$Key.Value)
|
||||
}
|
||||
|
||||
$result["dsc_attributes"] = $attrib
|
||||
$result["reboot_required"] = $false
|
||||
|
||||
$Config = @{
|
||||
Name = ($resourcename)
|
||||
Property = @{
|
||||
}
|
||||
}
|
||||
Property = @{}
|
||||
}
|
||||
|
||||
#Get the latest version of the module
|
||||
if ($module_version -eq "latest")
|
||||
|
@ -115,24 +209,24 @@ try {
|
|||
}
|
||||
catch {}
|
||||
|
||||
|
||||
#Convert params to correct datatype and inject
|
||||
$attrib.Keys | foreach-object {
|
||||
$Key = $_.replace("item_name", "name")
|
||||
$prop = $resource.Properties | where {$_.Name -eq $key}
|
||||
foreach ($attribute in $Attributes.GetEnumerator())
|
||||
{
|
||||
$key = $attribute.Name.Replace("item_name", "name")
|
||||
$value = $attribute.Value
|
||||
$prop = $resource.Properties | Where-Object {$_.Name -eq $key}
|
||||
if (!$prop)
|
||||
{
|
||||
#If its a credential specified as "credential", Ansible will support credential_username and credential_password. Need to check for that
|
||||
$prop = $resource.Properties | where {$_.Name -eq $key.Replace("_username","")}
|
||||
$prop = $resource.Properties | Where-Object {$_.Name -eq $key.Replace("_username","")}
|
||||
if ($prop)
|
||||
{
|
||||
#We need to construct a cred object. At this point keyvalue is the username, so grab the password
|
||||
$PropUserNameValue = $attrib.Item($_)
|
||||
$PropUserNameValue = $value
|
||||
$PropPassword = $key.Replace("_username","_password")
|
||||
$PropPasswordValue = $attrib.$PropPassword
|
||||
$PropPasswordValue = $Attributes.$PropPassword
|
||||
|
||||
$cred = New-Object System.Management.Automation.PSCredential ($PropUserNameValue, ($PropPasswordValue | ConvertTo-SecureString -AsPlainText -Force))
|
||||
[System.Management.Automation.PSCredential]$KeyValue = $cred
|
||||
$KeyValue = New-Object System.Management.Automation.PSCredential ($PropUserNameValue, ($PropPasswordValue | ConvertTo-SecureString -AsPlainText -Force))
|
||||
$config.Property.Add($key.Replace("_username",""),$KeyValue)
|
||||
}
|
||||
ElseIf ($key.Contains("_password"))
|
||||
|
@ -143,91 +237,21 @@ $attrib.Keys | foreach-object {
|
|||
{
|
||||
Fail-Json -obj $result -message "Property $key in resource $resourcename is not a valid property"
|
||||
}
|
||||
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[string]")
|
||||
Else
|
||||
{
|
||||
[String]$KeyValue = $attrib.Item($_)
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[string[]]")
|
||||
{
|
||||
#KeyValue is an array of strings
|
||||
[String]$TempKeyValue = $attrib.Item($_)
|
||||
[String[]]$KeyValue = $TempKeyValue.Split(",").Trim()
|
||||
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[UInt32[]]")
|
||||
{
|
||||
#KeyValue is an array of integers
|
||||
[String]$TempKeyValue = $attrib.Item($_)
|
||||
[UInt32[]]$KeyValue = $attrib.Item($_.split(",").Trim())
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[bool]")
|
||||
{
|
||||
if ($attrib.Item($_) -like "true")
|
||||
if ($value -eq $null)
|
||||
{
|
||||
[bool]$KeyValue = $true
|
||||
$keyValue = $null
|
||||
}
|
||||
ElseIf ($attrib.Item($_) -like "false")
|
||||
Else
|
||||
{
|
||||
[bool]$KeyValue = $false
|
||||
$keyValue = Parse-DscProperty -name $key -value $value -resourceProp $prop
|
||||
}
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[int]")
|
||||
{
|
||||
[int]$KeyValue = $attrib.Item($_)
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[CimInstance[]]")
|
||||
{
|
||||
#KeyValue is an array of CimInstance
|
||||
[CimInstance[]]$KeyVal = @()
|
||||
[String]$TempKeyValue = $attrib.Item($_)
|
||||
#Need to split on the string }, because some property values have commas in them
|
||||
[String[]]$KeyValueStr = $TempKeyValue -split("},")
|
||||
#Go through each string of properties and create a hash of them
|
||||
foreach($str in $KeyValueStr)
|
||||
{
|
||||
[string[]]$properties = $str.Split("{")[1].Replace("}","").Trim().Split([environment]::NewLine).Trim()
|
||||
$prph = @{}
|
||||
foreach($p in $properties)
|
||||
{
|
||||
$pArr = $p -split "="
|
||||
#if the value can be an int we must convert it to an int
|
||||
if([bool]($pArr[1] -as [int] -is [int]))
|
||||
{
|
||||
$prph.Add($pArr[0].Trim(),$pArr[1].Trim() -as [int])
|
||||
}
|
||||
else
|
||||
{
|
||||
$prph.Add($pArr[0].Trim(),$pArr[1].Trim())
|
||||
}
|
||||
}
|
||||
#create the new CimInstance
|
||||
$cim = New-CimInstance -ClassName $str.Split("{")[0].Trim() -Property $prph -ClientOnly
|
||||
#add the new CimInstance to the array
|
||||
$KeyVal += $cim
|
||||
}
|
||||
$config.Property.Add($key,$KeyVal)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[Int32]")
|
||||
{
|
||||
# Add Supoort for Int32
|
||||
[int]$KeyValue = $attrib.Item($_)
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
ElseIf ($prop.PropertyType -eq "[UInt32]")
|
||||
{
|
||||
# Add Support for [UInt32]
|
||||
[UInt32]$KeyValue = $attrib.Item($_)
|
||||
$config.Property.Add($key,$KeyValue)
|
||||
}
|
||||
|
||||
}
|
||||
$config.Property.Add($key, $keyValue)
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -262,6 +286,4 @@ Catch
|
|||
Fail-Json -obj $result -message $_[0].Exception.Message
|
||||
}
|
||||
|
||||
|
||||
#set-attr -obj $result -name "property" -value $property
|
||||
Exit-Json -obj $result
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2015, Trond Hindenes <trond@hindenes.com>, and others
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# this is a windows documentation stub. actual code lives in the .ps1
|
||||
# file of the same name
|
||||
# (c) 2015, Trond Hindenes <trond@hindenes.com>, and others
|
||||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
|
@ -31,70 +18,131 @@ module: win_dsc
|
|||
version_added: "2.4"
|
||||
short_description: Invokes a PowerShell DSC configuration
|
||||
description:
|
||||
- Invokes a PowerShell DSC Configuration. Requires PowerShell version 5 (February release or newer).
|
||||
- Most of the parameters for this module are dynamic and will vary depending on the DSC Resource.
|
||||
- See :doc:`windows_dsc` for more information on how to use this module.
|
||||
- Configures a resource using PowerShell DSC.
|
||||
- Requires PowerShell version 5.0 or newer.
|
||||
- Most of the options for this module are dynamic and will vary depending on
|
||||
the DSC Resource specified in I(resource_name).
|
||||
- See :doc:`windows_dsc` for more information on how to use this module.
|
||||
options:
|
||||
resource_name:
|
||||
description:
|
||||
- The DSC Resource to use. Must be accessible to PowerShell using any of the default paths.
|
||||
- The name of the DSC Resource to use.
|
||||
- Must be accessible to PowerShell using any of the default paths.
|
||||
required: true
|
||||
module_version:
|
||||
description:
|
||||
- Can be used to configure the exact version of the dsc resource to be invoked.
|
||||
- Useful if the target node has multiple versions installed of the module containing the DSC resource.
|
||||
- If not specified, the module will follow standard Powershell convention and use the highest version available.
|
||||
- Can be used to configure the exact version of the DSC resource to be
|
||||
invoked.
|
||||
- Useful if the target node has multiple versions installed of the module
|
||||
containing the DSC resource.
|
||||
- If not specified, the module will follow standard PowerShell convention
|
||||
and use the highest version available.
|
||||
default: latest
|
||||
author: Trond Hindenes
|
||||
free_form:
|
||||
description:
|
||||
- The M(win_dsc) module takes in multiple free form options based on the
|
||||
DSC resource being invoked by I(resource_name).
|
||||
- There is no option actually named C(free_form) so see the examples.
|
||||
- This module will try and convert the option to the correct type required
|
||||
by the DSC resource and throw a warning if it fails.
|
||||
- If the type of the DSC resource option is a C(CimInstance) or
|
||||
C(CimInstance[]), this means the value should be a dictionary or list
|
||||
of dictionaries based on the values required by that option.
|
||||
- If the type of the DSC resource option is a C(PSCredential) then there
|
||||
needs to be 2 options set in the Ansible task definition suffixed with
|
||||
C(_username) and C(_password).
|
||||
- If the type of the DSC resource option is an array, then a list should be
|
||||
provided but a comma separated string also work. Use a list where
|
||||
possible as no escaping is required and it works with more complex types
|
||||
list C(CimInstance[]).
|
||||
required: true
|
||||
notes:
|
||||
- By default there are a few builtin resources that come with PowerShell 5.0,
|
||||
see U(https://docs.microsoft.com/en-us/powershell/dsc/builtinresource) for
|
||||
more information on these resources.
|
||||
- Custom DSC resources can be installed with M(win_psmodule) using the I(name)
|
||||
option.
|
||||
- The DSC engine run's each task as the SYSTEM account, any resources that need
|
||||
to be accessed with a different account need to have C(PsDscRunAsCredential)
|
||||
set.
|
||||
author:
|
||||
- Trond Hindenes (@trondhindenes)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
# Playbook example
|
||||
- name: Extract zip file
|
||||
win_dsc:
|
||||
resource_name: archive
|
||||
ensure: Present
|
||||
path: "C:\\Temp\\zipfile.zip"
|
||||
destination: "C:\\Temp\\Temp2"
|
||||
- name: Extract zip file
|
||||
win_dsc:
|
||||
resource_name: Archive
|
||||
Ensure: Present
|
||||
Path: C:\Temp\zipfile.zip
|
||||
Destination: C:\Temp\Temp2
|
||||
|
||||
- name: Invoke DSC with check mode
|
||||
win_dsc:
|
||||
resource_name: windowsfeature
|
||||
name: telnet-client
|
||||
- name: Install a Windows feature with the WindowsFeature resource
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: telnet-client
|
||||
|
||||
- name: Edit HKCU reg key under specific user
|
||||
win_regedit:
|
||||
resource_name: Registry
|
||||
Ensure: Present
|
||||
Key: HKEY_CURRENT_USER\ExampleKey
|
||||
ValueName: TestValue
|
||||
ValueData: TestData
|
||||
PsDscRunAsCredential_username: '{{ansible_user}}'
|
||||
PsDscRunAsCredentual_password: '{{ansible_password}}'
|
||||
no_log: true
|
||||
|
||||
- name: Create file with multiple attributes
|
||||
win_dsc:
|
||||
resource_name: File
|
||||
DestinationPath: C:\ansible\dsc
|
||||
Attributes: # can also be a comma separated string, e.g. 'Hidden, System'
|
||||
- Hidden
|
||||
- System
|
||||
Ensure: Present
|
||||
Type: Directory
|
||||
|
||||
# more complex example using custom DSC resource and dict values
|
||||
- name: Setup the xWebAdministration module
|
||||
win_psmodule:
|
||||
name: xWebAdministration
|
||||
state: present
|
||||
|
||||
- name: Create IIS Website with Binding and Authentication options
|
||||
win_dsc:
|
||||
resource_name: xWebsite
|
||||
Ensure: Present
|
||||
Name: DSC Website
|
||||
State: Started
|
||||
PhysicalPath: C:\inetpub\wwwroot
|
||||
BindingInfo: # Example of a CimInstance[] DSC parameter (list of dicts)
|
||||
- Protocol: https
|
||||
Port: 1234
|
||||
CertificateStoreName: MY
|
||||
CertificateThumbprint: C676A89018C4D5902353545343634F35E6B3A659
|
||||
HostName: DSCTest
|
||||
IPAddress: '*'
|
||||
SSLFlags: '1'
|
||||
- Protocol: http
|
||||
Port: 4321
|
||||
IPAddress: '*'
|
||||
AuthenticationInfo: # Example of a CimInstance DSC parameter (dict)
|
||||
Anonymous: no
|
||||
Basic: true
|
||||
Digest: false
|
||||
Windows: yes
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
resource_name:
|
||||
description: The name of the invoked resource
|
||||
returned: always
|
||||
type: string
|
||||
sample: windowsfeature
|
||||
module_version:
|
||||
description: The version of the dsc resource/module used.
|
||||
returned: success
|
||||
type: string
|
||||
sample: "1.0.1"
|
||||
attributes:
|
||||
description: The attributes/parameters passed in to the DSC resource as key/value pairs
|
||||
returned: always
|
||||
type: complex
|
||||
sample:
|
||||
contains:
|
||||
Key:
|
||||
description: Attribute key
|
||||
Value:
|
||||
description: Attribute value
|
||||
dsc_attributes:
|
||||
description: The attributes/parameters as returned from the DSC engine in dict format
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
Key:
|
||||
description: Attribute key
|
||||
Value:
|
||||
description: Attribute value
|
||||
reboot_required:
|
||||
description: flag returned from the DSC engine indicating whether or not the machine requires a reboot for the invoked changes to take effect
|
||||
description: Flag returned from the DSC engine indicating whether or not
|
||||
the machine requires a reboot for the invoked changes to take effect.
|
||||
returned: always
|
||||
type: boolean
|
||||
sample: True
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
|
||||
# Feature not normally installed by default.
|
||||
test_win_feature_name: Telnet-Client
|
||||
test_win_dsc_feature_name: Telnet-Client
|
||||
test_win_dsc_folder: C:\ansible test
|
||||
test_win_dsc_run_desctructive: no
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
xTestResource Version: 2.0.0
|
||||
|
||||
Ensure:
|
||||
Type: System.String
|
||||
Value: Present
|
||||
|
||||
StringParam:
|
||||
Type: System.String
|
||||
Value: string param
|
||||
|
||||
UInt32Param:
|
||||
Type: System.UInt32
|
||||
Value: 1000
|
||||
|
||||
UInt64Param:
|
||||
Type: System.UInt64
|
||||
Value: 1000000
|
||||
|
||||
StringArrayParam:
|
||||
Type: System.String[]
|
||||
Value: [ "string 1", "string 2" ]
|
||||
|
||||
UInt32ArrayParam:
|
||||
Type: System.UInt32[]
|
||||
Value: [ 1000, 2000 ]
|
||||
|
||||
UInt64ArrayParam:
|
||||
Type: System.UInt64[]
|
||||
Value: [ 1000000, 2000000 ]
|
||||
|
||||
BooleanParam:
|
||||
Type: System.Boolean
|
||||
Value: True
|
||||
|
||||
PSCredentialParam:
|
||||
Type: System.Management.Automation.PSCredential
|
||||
Username: username
|
||||
Password: password
|
||||
|
||||
CimInstanceParam:
|
||||
Type: Microsoft.Management.Infrastructure.CimInstance
|
||||
|
||||
CimInstanceArrayParam:
|
||||
Type: Microsoft.Management.Infrastructure.CimInstance[]
|
|
@ -0,0 +1,44 @@
|
|||
xTestResource Version: 1.0.0
|
||||
|
||||
Ensure:
|
||||
Type: System.String
|
||||
Value: Present
|
||||
|
||||
StringParam:
|
||||
Type: System.String
|
||||
Value: string param
|
||||
|
||||
UInt32Param:
|
||||
Type: System.UInt32
|
||||
Value: 1000
|
||||
|
||||
UInt64Param:
|
||||
Type: System.UInt64
|
||||
Value: 1000000
|
||||
|
||||
StringArrayParam:
|
||||
Type: System.String[]
|
||||
Value: [ "string 1", "string 2" ]
|
||||
|
||||
UInt32ArrayParam:
|
||||
Type: System.UInt32[]
|
||||
Value: [ 1000, 2000 ]
|
||||
|
||||
UInt64ArrayParam:
|
||||
Type: System.UInt64[]
|
||||
Value: [ 1000000, 2000000 ]
|
||||
|
||||
BooleanParam:
|
||||
Type: System.Boolean
|
||||
Value: True
|
||||
|
||||
PSCredentialParam:
|
||||
Type: System.Management.Automation.PSCredential
|
||||
Username: username
|
||||
Password: password
|
||||
|
||||
CimInstanceParam:
|
||||
Type: Microsoft.Management.Infrastructure.CimInstance
|
||||
|
||||
CimInstanceArrayParam:
|
||||
Type: Microsoft.Management.Infrastructure.CimInstance[]
|
|
@ -0,0 +1,16 @@
|
|||
# (c) 2017 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
|
||||
|
||||
class FilterModule(object):
|
||||
def filters(self):
|
||||
return {
|
||||
'strip_newline': self.strip_newline
|
||||
}
|
||||
|
||||
def strip_newline(self, value):
|
||||
# will convert \r\n and \n to just \n
|
||||
split_lines = value.splitlines()
|
||||
|
||||
return "\n".join(split_lines)
|
|
@ -0,0 +1,41 @@
|
|||
#!powershell
|
||||
# This file is part of Ansible
|
||||
|
||||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
|
||||
Import-Module -Name WebAdministration
|
||||
$params = Parse-Args $args -supports_check_mode $true
|
||||
$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true
|
||||
|
||||
$site = Get-Website -Name $name
|
||||
|
||||
$result = @{}
|
||||
if ($site -eq $null) {
|
||||
$result.exists = $false
|
||||
} else {
|
||||
$result.exists = $true
|
||||
$site_config = Get-WebConfiguration -Filter "System.WebServer/Security/Authentication/*" -PSPath "IIS:\Sites\$name"
|
||||
$http_bindings = $site.bindings.Collection | Where-Object { $_.protocol -eq "http" }
|
||||
$https_bindings = $site.bindings.Collection | Where-Object { $_.protocol -eq "https" }
|
||||
|
||||
$result.http = @{
|
||||
binding = $http_bindings.bindingInformation
|
||||
}
|
||||
$result.https = @{
|
||||
binding = $https_bindings.bindingInformation
|
||||
sslFlags = $https_bindings.sslFlags
|
||||
store = ($https_bindings.Attributes | Where-Object { $_.Name -eq "certificateStoreName" }).Value
|
||||
hash = ($https_bindings.Attributes | Where-Object { $_.Name -eq "certificateHash" }).Value
|
||||
}
|
||||
$result.auth = @{
|
||||
anonymous = ($site_config | Where-Object { $_.ElementTagName -like "*anonymous*" }).enabled
|
||||
basic = ($site_config | Where-Object { $_.ElementTagName -like "*basic*" }).enabled
|
||||
digest = ($site_config | Where-Object { $_.ElementTagName -like "*digest*" }).enabled
|
||||
windows = ($site_config | Where-Object { $_.ElementTagName -like "*windows*" }).enabled
|
||||
}
|
||||
}
|
||||
|
||||
Exit-Json -obj $result
|
135
test/integration/targets/win_dsc/tasks/destructive.yml
Normal file
135
test/integration/targets/win_dsc/tasks/destructive.yml
Normal file
|
@ -0,0 +1,135 @@
|
|||
# these tests are destructive and can be run manually on a throwaway host
|
||||
# set test_win_dsc_run_desctructive: yes in default/main.yml
|
||||
---
|
||||
- name: ensure IIS features are installed
|
||||
win_feature:
|
||||
name: Web-Server
|
||||
include_sub_features: yes
|
||||
include_management_tools: no
|
||||
state: present
|
||||
|
||||
- name: install xWebAdministration module
|
||||
win_psmodule:
|
||||
name: xWebAdministration
|
||||
state: present
|
||||
|
||||
- name: ensure IIS website does not exists
|
||||
win_iis_website:
|
||||
name: Ansible DSC Test
|
||||
state: absent
|
||||
|
||||
- name: get certificate hash for IIS test
|
||||
win_shell: (Get-ChildItem -Path Cert:\LocalMachine\My)[0].Thumbprint
|
||||
register: win_dsc_cert_thumbprint
|
||||
|
||||
- name: create an IIS website with auth and binding info (check mode)
|
||||
win_dsc:
|
||||
resource_name: xWebSite
|
||||
Ensure: Present
|
||||
Name: Ansible DSC Test
|
||||
State: Started
|
||||
PhysicalPath: C:\inetpub\wwwroot
|
||||
BindingInfo:
|
||||
- Protocol: https
|
||||
Port: 8443
|
||||
CertificateStoreName: MY
|
||||
CertificateThumbprint: '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
|
||||
HostName: DSCTest
|
||||
IPAddress: '*'
|
||||
SSLFlags: '1'
|
||||
- Protocol: http
|
||||
Port: 8888
|
||||
IPAddress: '*'
|
||||
AuthenticationInfo:
|
||||
Anonymous: yes
|
||||
Basic: no
|
||||
Digest: no
|
||||
Windows: yes
|
||||
register: win_dsc_iis_check
|
||||
check_mode: yes
|
||||
|
||||
- name: get result of create an IIS website (check mode)
|
||||
test_win_dsc_iis_info:
|
||||
name: Ansible DSC Test
|
||||
register: win_dsc_iis_check_result
|
||||
|
||||
- name: assert results of create an IIS website (check mode)
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_iis_check|changed
|
||||
- win_dsc_iis_check_result.exists == False
|
||||
|
||||
- name: create an IIS website with auth and binding info
|
||||
win_dsc:
|
||||
resource_name: xWebSite
|
||||
Ensure: Present
|
||||
Name: Ansible DSC Test
|
||||
State: Started
|
||||
PhysicalPath: C:\inetpub\wwwroot
|
||||
BindingInfo:
|
||||
- Protocol: https
|
||||
Port: 8443
|
||||
CertificateStoreName: MY
|
||||
CertificateThumbprint: '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
|
||||
HostName: Test
|
||||
IPAddress: '*'
|
||||
SSLFlags: '1'
|
||||
- Protocol: http
|
||||
Port: 8888
|
||||
IPAddress: '*'
|
||||
AuthenticationInfo:
|
||||
Anonymous: yes
|
||||
Basic: no
|
||||
Digest: no
|
||||
Windows: yes
|
||||
register: win_dsc_iis
|
||||
|
||||
- name: get result of create an IIS website
|
||||
test_win_dsc_iis_info:
|
||||
name: Ansible DSC Test
|
||||
register: win_dsc_iis_result
|
||||
|
||||
- name: assert results of create an IIS website
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_iis|changed
|
||||
- win_dsc_iis_result.exists == True
|
||||
- win_dsc_iis_result.auth.anonymous == True
|
||||
- win_dsc_iis_result.auth.basic == False
|
||||
- win_dsc_iis_result.auth.digest == False
|
||||
- win_dsc_iis_result.auth.windows == True
|
||||
- win_dsc_iis_result.http.binding == "*:8888:"
|
||||
- win_dsc_iis_result.https.binding == "*:8443:Test"
|
||||
- win_dsc_iis_result.https.hash == '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
|
||||
- win_dsc_iis_result.https.sslFlags == 1
|
||||
- win_dsc_iis_result.https.store == "MY"
|
||||
|
||||
- name: create an IIS website with auth and binding info (idempotent)
|
||||
win_dsc:
|
||||
resource_name: xWebSite
|
||||
Ensure: Present
|
||||
Name: Ansible DSC Test
|
||||
State: Started
|
||||
PhysicalPath: C:\inetpub\wwwroot
|
||||
BindingInfo:
|
||||
- Protocol: https
|
||||
Port: 8443
|
||||
CertificateStoreName: MY
|
||||
CertificateThumbprint: '{{win_dsc_cert_thumbprint.stdout_lines[0]}}'
|
||||
HostName: Test
|
||||
IPAddress: '*'
|
||||
SSLFlags: '1'
|
||||
- Protocol: http
|
||||
Port: 8888
|
||||
IPAddress: '*'
|
||||
AuthenticationInfo:
|
||||
Anonymous: yes
|
||||
Basic: no
|
||||
Digest: no
|
||||
Windows: yes
|
||||
register: win_dsc_iis_again
|
||||
|
||||
- name: assert results of create an IIS website (idempotent)
|
||||
assert:
|
||||
that:
|
||||
- not win_dsc_iis_again|changed
|
|
@ -1,119 +1,34 @@
|
|||
# test code for the win_feature module
|
||||
# (c) 2014, Chris Church <chris@ninemoreminutes.com>
|
||||
---
|
||||
- name: get powershell version
|
||||
win_shell: $PSVersionTable.PSVersion.Major
|
||||
register: powershell_version
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
- name: run smoke tests when we can't run the full suite
|
||||
include_tasks: smoke.yml
|
||||
when: powershell_version.stdout_lines[0]|int < 5
|
||||
|
||||
- block:
|
||||
- name: run non-destructive tests
|
||||
include_tasks: tests.yml
|
||||
|
||||
- name: check whether servermanager module is available (windows 2008 r2 or later)
|
||||
raw: PowerShell -Command Import-Module ServerManager
|
||||
register: win_feature_has_servermanager
|
||||
ignore_errors: true
|
||||
- name: run destructive tests if flag is set
|
||||
include_tasks: destructive.yml
|
||||
when: test_win_dsc_run_desctructive == True
|
||||
|
||||
always:
|
||||
- name: remove test feature
|
||||
win_feature:
|
||||
name: '{{test_win_dsc_feature_name}}'
|
||||
state: absent
|
||||
|
||||
- name: start with feature absent
|
||||
win_feature:
|
||||
name: "{{ test_win_feature_name }}"
|
||||
state: absent
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
- name: remove test folder
|
||||
win_file:
|
||||
path: '{{test_win_dsc_folder}}'
|
||||
state: absent
|
||||
|
||||
- name: Invoke DSC with check mode
|
||||
win_dsc:
|
||||
resource_name: windowsfeature
|
||||
name: "{{ test_win_feature_name }}"
|
||||
check_mode: yes
|
||||
register: win_dsc_checkmode_result
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
- name: remove custom DSC resource folder
|
||||
win_file:
|
||||
path: C:\Program Files\WindowsPowerShell\Modules\xTestDsc
|
||||
state: absent
|
||||
|
||||
- name: check result of Invoke DSC with check mode
|
||||
assert:
|
||||
that:
|
||||
- "win_dsc_checkmode_result|changed"
|
||||
- "win_dsc_checkmode_result|success"
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: Make sure the feature is still absent
|
||||
win_dsc:
|
||||
resource_name: windowsfeature
|
||||
name: "{{ test_win_feature_name }}"
|
||||
ensure: absent
|
||||
register: win_dsc_1_result
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: check result of Make sure the feature is still absent
|
||||
assert:
|
||||
that:
|
||||
- "not win_dsc_1_result|changed"
|
||||
- "win_dsc_1_result|success"
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: Install feature for realz
|
||||
win_dsc:
|
||||
resource_name: windowsfeature
|
||||
name: "{{ test_win_feature_name }}"
|
||||
register: win_dsc_2_result
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: check result of Install feature for realz
|
||||
assert:
|
||||
that:
|
||||
- "win_dsc_2_result|changed"
|
||||
- "win_dsc_2_result|success"
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: Ensure clean failure
|
||||
win_dsc:
|
||||
resource_name: some_unknown_resource_that_wont_ever_exist
|
||||
name: "{{ test_win_feature_name }}"
|
||||
register: win_dsc_3_result
|
||||
ignore_errors: true
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: check result of Ensure clean failure
|
||||
assert:
|
||||
that:
|
||||
- "not win_dsc_3_result|changed"
|
||||
- "not win_dsc_3_result|success"
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: Make sure the feature is absent
|
||||
win_dsc:
|
||||
resource_name: windowsfeature
|
||||
name: "{{ test_win_feature_name }}"
|
||||
ensure: absent
|
||||
register: win_dsc_4_result
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: check result of Make sure the feature is absent
|
||||
assert:
|
||||
that:
|
||||
- "win_dsc_4_result|changed"
|
||||
- "win_dsc_4_result|success"
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: Make sure the feature is still absent with no changes
|
||||
win_dsc:
|
||||
resource_name: windowsfeature
|
||||
name: "{{ test_win_feature_name }}"
|
||||
ensure: absent
|
||||
register: win_dsc_5_result
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
|
||||
- name: check result of Make sure the feature is absent
|
||||
assert:
|
||||
that:
|
||||
- "not win_dsc_5_result|changed"
|
||||
- "win_dsc_5_result|success"
|
||||
when: (win_feature_has_servermanager|success) and (ansible_powershell_version is defined) and (ansible_powershell_version >= 5)
|
||||
when: powershell_version.stdout_lines[0]|int >= 5
|
||||
|
|
8
test/integration/targets/win_dsc/tasks/smoke.yml
Normal file
8
test/integration/targets/win_dsc/tasks/smoke.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# basic smoke tests run on hosts that cannot run DSC, verifies the code is at
|
||||
# least runnable
|
||||
---
|
||||
- name: expect failure when running on old PS hosts
|
||||
win_dsc:
|
||||
resource_name: File
|
||||
register: fail_dsc_old
|
||||
failed_when: '"This module cannot run as it requires a minimum PowerShell version of 5.0, actual was " not in fail_dsc_old.msg'
|
330
test/integration/targets/win_dsc/tasks/tests.yml
Normal file
330
test/integration/targets/win_dsc/tasks/tests.yml
Normal file
|
@ -0,0 +1,330 @@
|
|||
# slightly non-destructive tests that will run if WMF 5.0 is installed
|
||||
---
|
||||
- name: start with feature absent
|
||||
win_feature:
|
||||
name: '{{test_win_dsc_feature_name}}'
|
||||
state: absent
|
||||
|
||||
- name: fail with incorrect DSC resource name
|
||||
win_dsc:
|
||||
resource_name: FakeResource
|
||||
Name: fake
|
||||
register: fail_invalid_resource
|
||||
failed_when: fail_invalid_resource.msg != "Resource FakeResource not found"
|
||||
|
||||
- name: fail by not setting mandatory option
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Ensure: Present
|
||||
register: fail_missing_mandatory
|
||||
failed_when: fail_missing_mandatory.msg != "Could not find mandatory property Name. Add this property and try again."
|
||||
|
||||
- name: fail to add a non-existant feature
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: InvalidFeature
|
||||
Ensure: Present
|
||||
register: fail_invalid_feature
|
||||
failed_when: '"The requested feature InvalidFeature is not found on the target machine" not in fail_invalid_feature.msg'
|
||||
|
||||
- name: add Windows feature (check mode)
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: '{{test_win_dsc_feature_name}}'
|
||||
Ensure: Present
|
||||
register: win_dsc_add_feature_check
|
||||
check_mode: yes
|
||||
|
||||
- name: get result of add Windows feature (check mode)
|
||||
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
|
||||
register: win_dsc_add_feature_result_check
|
||||
|
||||
- name: assert result of add Windows feature (check mode)
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_add_feature_check|changed
|
||||
- win_dsc_add_feature_result_check.stdout == "False\r\n"
|
||||
|
||||
- name: add Windows feature
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: '{{test_win_dsc_feature_name}}'
|
||||
Ensure: Present
|
||||
register: win_dsc_add_feature
|
||||
|
||||
- name: get result of add Windows feature
|
||||
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
|
||||
register: win_dsc_add_feature_result
|
||||
|
||||
- name: assert result of add Windows feature
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_add_feature|changed
|
||||
- win_dsc_add_feature_result.stdout == "True\r\n"
|
||||
|
||||
- name: add Windows feature (idempotent)
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: '{{test_win_dsc_feature_name}}'
|
||||
Ensure: Present
|
||||
register: win_dsc_add_feature_again
|
||||
|
||||
- name: assert result of add Windows feature (idempotent)
|
||||
assert:
|
||||
that:
|
||||
- not win_dsc_add_feature_again|changed
|
||||
|
||||
- name: remove Windows feature (check mode)
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: '{{test_win_dsc_feature_name}}'
|
||||
Ensure: Absent
|
||||
register: win_dsc_remove_feature_check
|
||||
check_mode: yes
|
||||
|
||||
- name: get result of remove Windows feature (check mode)
|
||||
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
|
||||
register: win_dsc_remove_feature_result_check
|
||||
|
||||
- name: assert result of remove Windows feature (check mode)
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_remove_feature_check|changed
|
||||
- win_dsc_remove_feature_result_check.stdout == "True\r\n"
|
||||
|
||||
- name: remove Windows feature
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: '{{test_win_dsc_feature_name}}'
|
||||
Ensure: Absent
|
||||
register: win_dsc_remove_feature
|
||||
|
||||
- name: get result of remove Windows feature
|
||||
win_shell: (Get-WindowsFeature -Name {{test_win_dsc_feature_name}}).Installed
|
||||
register: win_dsc_remove_feature_result
|
||||
|
||||
- name: assert result of remove Windows feature
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_remove_feature|changed
|
||||
- win_dsc_remove_feature_result.stdout == "False\r\n"
|
||||
|
||||
- name: remove Windows feature (idempotent)
|
||||
win_dsc:
|
||||
resource_name: WindowsFeature
|
||||
Name: '{{test_win_dsc_feature_name}}'
|
||||
Ensure: Absent
|
||||
register: win_dsc_remove_feature_again
|
||||
|
||||
- name: assert result of remove Windows feature (idempotent)
|
||||
assert:
|
||||
that:
|
||||
- not win_dsc_remove_feature_again|changed
|
||||
|
||||
- name: ensure test folder doesn't exist before test
|
||||
win_file:
|
||||
path: '{{test_win_dsc_folder}}'
|
||||
state: absent
|
||||
|
||||
- name: create test file (check mode)
|
||||
win_dsc:
|
||||
resource_name: File
|
||||
DestinationPath: '{{test_win_dsc_folder}}\dsc-file'
|
||||
Contents: file contents
|
||||
Attributes:
|
||||
- Hidden
|
||||
- ReadOnly
|
||||
Ensure: Present
|
||||
Type: File
|
||||
register: win_dsc_create_file_check
|
||||
check_mode: yes
|
||||
|
||||
- name: get result of create test file (check mode)
|
||||
win_stat:
|
||||
path: '{{test_win_dsc_folder}}\dsc-file'
|
||||
register: win_dsc_create_file_result_check
|
||||
|
||||
- name: assert results of create test file (check mode)
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_create_file_check|changed
|
||||
- win_dsc_create_file_result_check.stat.exists == False
|
||||
|
||||
- name: create test file
|
||||
win_dsc:
|
||||
resource_name: File
|
||||
DestinationPath: '{{test_win_dsc_folder}}\dsc-file'
|
||||
Contents: file contents
|
||||
Attributes:
|
||||
- Hidden
|
||||
- ReadOnly
|
||||
Ensure: Present
|
||||
Type: File
|
||||
register: win_dsc_create_file
|
||||
|
||||
- name: get result of create test file
|
||||
win_stat:
|
||||
path: '{{test_win_dsc_folder}}\dsc-file'
|
||||
register: win_dsc_create_file_result
|
||||
|
||||
- name: assert results of create test file
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_create_file|changed
|
||||
- win_dsc_create_file_result.stat.exists == True
|
||||
- win_dsc_create_file_result.stat.isdir == False
|
||||
- win_dsc_create_file_result.stat.ishidden == True
|
||||
- win_dsc_create_file_result.stat.isreadonly == True
|
||||
|
||||
- name: create test file (idempotent)
|
||||
win_dsc:
|
||||
resource_name: File
|
||||
DestinationPath: '{{test_win_dsc_folder}}\dsc-file'
|
||||
Contents: file contents
|
||||
Attributes: Hidden, ReadOnly
|
||||
Ensure: Present
|
||||
Type: File
|
||||
register: win_dsc_create_file_again
|
||||
|
||||
- name: assert results of create test file (idempotent)
|
||||
assert:
|
||||
that:
|
||||
- not win_dsc_create_file_again|changed
|
||||
|
||||
- name: get SID of current ansible user
|
||||
win_shell: (New-Object System.Security.Principal.NTAccount("{{ansible_user}}")).Translate([System.Security.Principal.SecurityIdentifier]).ToString()
|
||||
register: win_dsc_actual_sid
|
||||
|
||||
- name: run DSC process as another user
|
||||
win_dsc:
|
||||
resource_name: Script
|
||||
GetScript: '@{ Result = "" }'
|
||||
SetScript: |
|
||||
$output = &whoami.exe
|
||||
$sid = (New-Object System.Security.Principal.NTAccount($output)).Translate([System.Security.Principal.SecurityIdentifier]).ToString()
|
||||
Set-Content -Path "{{test_win_dsc_folder}}\file" -Value $sid
|
||||
TestScript: Test-Path -Path "{{test_win_dsc_folder}}\file"
|
||||
PsDscRunAsCredential_username: '{{ansible_user}}'
|
||||
PsDscRunAsCredential_password: '{{ansible_password}}'
|
||||
register: win_dsc_runas
|
||||
|
||||
- name: get content of script output file
|
||||
slurp:
|
||||
path: '{{test_win_dsc_folder}}\file'
|
||||
register: win_dsc_runas_result
|
||||
|
||||
- name: assert results of run DSC process as another user
|
||||
assert:
|
||||
that:
|
||||
- win_dsc_runas|changed
|
||||
- win_dsc_runas_result.content|b64decode == win_dsc_actual_sid.stdout
|
||||
|
||||
- name: create custom DSC resource folder
|
||||
win_file:
|
||||
path: C:\Program Files\WindowsPowerShell\Modules\xTestDsc\{{item}}\DSCResources\ANSIBLE_xTestResource
|
||||
state: directory
|
||||
with_items:
|
||||
- "1.0.0"
|
||||
- "2.0.0"
|
||||
|
||||
- name: template custom DSC resource files
|
||||
win_template:
|
||||
src: '{{item.src}}'
|
||||
dest: C:\Program Files\WindowsPowerShell\Modules\xTestDsc\{{item.version}}\{{item.dest}}
|
||||
with_items:
|
||||
- src: ANSIBLE_xTestResource.schema.mof
|
||||
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.schema.mof
|
||||
version: "1.0.0"
|
||||
- src: ANSIBLE_xTestResource.psm1
|
||||
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.psm1
|
||||
version: "1.0.0"
|
||||
- src: xTestDsc.psd1
|
||||
dest: xTestDsc.psd1
|
||||
version: "1.0.0"
|
||||
- src: ANSIBLE_xTestResource.schema.mof
|
||||
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.schema.mof
|
||||
version: "2.0.0"
|
||||
- src: ANSIBLE_xTestResource.psm1
|
||||
dest: DSCResources\ANSIBLE_xTestResource\ANSIBLE_xTestResource.psm1
|
||||
version: "2.0.0"
|
||||
- src: xTestDsc.psd1
|
||||
dest: xTestDsc.psd1
|
||||
version: "2.0.0"
|
||||
|
||||
- name: run custom DSC resource
|
||||
win_dsc: &dsc_params
|
||||
resource_name: xTestResource
|
||||
Path: '{{test_win_dsc_folder}}\custom-output.txt'
|
||||
Ensure: Present
|
||||
StringParam: string param
|
||||
UInt32Param: 1000
|
||||
UInt64Param: 1000000
|
||||
StringArrayParam:
|
||||
- string 1
|
||||
- string 2
|
||||
UInt32ArrayParam:
|
||||
- 1000
|
||||
- 2000
|
||||
UInt64ArrayParam:
|
||||
- 1000000
|
||||
- 2000000
|
||||
BooleanParam: yes
|
||||
PSCredentialParam_username: username
|
||||
PSCredentialParam_password: password
|
||||
CimInstanceParam:
|
||||
StringKey: a
|
||||
BooleanKey: yes
|
||||
UInt32Key: 1
|
||||
StringArrayKey:
|
||||
- string 1
|
||||
- string 2
|
||||
CimInstanceArrayParam:
|
||||
- StringKey: b
|
||||
BooleanKey: no
|
||||
UInt32Key: 2
|
||||
StringArrayKey:
|
||||
- string 3
|
||||
- string 4
|
||||
- StringKey: c
|
||||
BooleanKey: no
|
||||
UInt32Key: 3
|
||||
StringArrayKey:
|
||||
- string 5
|
||||
- string 6
|
||||
register: test_dsc_custom
|
||||
|
||||
- name: get output of custom DSC resource
|
||||
slurp:
|
||||
path: '{{test_win_dsc_folder}}\custom-output.txt'
|
||||
register: test_dsc_custom_output
|
||||
|
||||
- name: get expected output of custom DSC resource
|
||||
set_fact:
|
||||
test_dsc_custom_expected: '{{lookup("file", "custom-result-normal.txt")}}'
|
||||
|
||||
- name: assert result of custom DSC resource
|
||||
assert:
|
||||
that:
|
||||
- test_dsc_custom|changed
|
||||
- test_dsc_custom_output.content|b64decode|strip_newline == test_dsc_custom_expected|strip_newline
|
||||
|
||||
- name: run custom DSC resource with version
|
||||
win_dsc:
|
||||
<<: *dsc_params
|
||||
module_version: '1.0.0'
|
||||
register: test_dsc_custom_version
|
||||
|
||||
- name: get output of custom DSC resource with version
|
||||
slurp:
|
||||
path: '{{test_win_dsc_folder}}\custom-output.txt'
|
||||
register: test_dsc_custom_output_version
|
||||
|
||||
- name: get expected output of custom DSC resource with version
|
||||
set_fact:
|
||||
test_dsc_custom_expected_version: '{{lookup("file", "custom-result-versioned.txt")}}'
|
||||
|
||||
- name: assert result of custom DSC resource with version
|
||||
assert:
|
||||
that:
|
||||
- test_dsc_custom|changed
|
||||
- test_dsc_custom_output_version.content|b64decode|strip_newline == test_dsc_custom_expected_version|strip_newline
|
|
@ -0,0 +1,173 @@
|
|||
#Requires -Version 5.0 -Modules CimCmdlets
|
||||
|
||||
Function Get-TargetResource
|
||||
{
|
||||
[CmdletBinding()]
|
||||
[OutputType([Hashtable])]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("Present", "Absent")]
|
||||
[String]
|
||||
$Ensure = "Present",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$Path
|
||||
)
|
||||
return @{
|
||||
Ensure = $Ensure
|
||||
Path = $Path
|
||||
}
|
||||
}
|
||||
|
||||
Function Set-TargetResource
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("Present", "Absent")]
|
||||
[String]
|
||||
$Ensure = "Present",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$Path,
|
||||
|
||||
[String]
|
||||
$StringParam,
|
||||
|
||||
[UInt32]
|
||||
$UInt32Param,
|
||||
|
||||
[UInt64]
|
||||
$UInt64Param,
|
||||
|
||||
[String[]]
|
||||
$StringArrayParam,
|
||||
|
||||
[UInt32[]]
|
||||
$UInt32ArrayParam,
|
||||
|
||||
[UInt64[]]
|
||||
$UInt64ArrayParam,
|
||||
|
||||
[Boolean]
|
||||
$BooleanParam,
|
||||
|
||||
[PSCredential]
|
||||
$PSCredentialParam,
|
||||
|
||||
[Microsoft.Management.Infrastructure.CimInstance]
|
||||
$CimInstanceParam,
|
||||
|
||||
[Microsoft.Management.Infrastructure.CimInstance[]]
|
||||
$CimInstanceArrayParam
|
||||
)
|
||||
|
||||
$file_contents = @"
|
||||
xTestResource Version: {{item.version}}
|
||||
|
||||
Ensure:
|
||||
Type: $($Ensure.GetType().FullName)
|
||||
Value: $($Ensure.ToString())
|
||||
|
||||
StringParam:
|
||||
Type: $($StringParam.GetType().FullName)
|
||||
Value: $($StringParam)
|
||||
|
||||
UInt32Param:
|
||||
Type: $($UInt32Param.GetType().FullName)
|
||||
Value: $($UInt32Param.ToString())
|
||||
|
||||
UInt64Param:
|
||||
Type: $($UInt64Param.GetType().FullName)
|
||||
Value: $($UInt64Param.ToString())
|
||||
|
||||
StringArrayParam:
|
||||
Type: $($StringArrayParam.GetType().FullName)
|
||||
Value: [ "$($StringArrayParam -join '", "')" ]
|
||||
|
||||
UInt32ArrayParam:
|
||||
Type: $($UInt32ArrayParam.GetType().FullName)
|
||||
Value: [ $($UInt32ArrayParam -join ', ') ]
|
||||
|
||||
UInt64ArrayParam:
|
||||
Type: $($UInt64ArrayParam.GetType().FullName)
|
||||
Value: [ $($UInt64ArrayParam -join ', ') ]
|
||||
|
||||
BooleanParam:
|
||||
Type: $($BooleanParam.GetType().FullName)
|
||||
Value: $($BooleanParam.ToString())
|
||||
|
||||
PSCredentialParam:
|
||||
Type: $($PSCredentialParam.GetType().FullName)
|
||||
Username: $($PSCredentialParam.GetNetworkCredential().Username)
|
||||
Password: $($PSCredentialParam.GetNetworkCredential().Password)
|
||||
|
||||
CimInstanceParam:
|
||||
Type: $($CimInstanceParam.GetType().FullName)
|
||||
|
||||
CimInstanceArrayParam:
|
||||
Type: $($CimInstanceArrayParam.GetType().FullName)
|
||||
"@
|
||||
if (Test-Path -Path $Path)
|
||||
{
|
||||
Remove-Item -Path $Path -Force > $null
|
||||
}
|
||||
New-Item -Path $Path -ItemType File > $null
|
||||
Set-Content -Path $Path -Value $file_contents > $null
|
||||
}
|
||||
|
||||
Function Test-TargetResource
|
||||
{
|
||||
[CmdletBinding()]
|
||||
[OutputType([Boolean])]
|
||||
param
|
||||
(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("Present", "Absent")]
|
||||
[String]
|
||||
$Ensure = "Present",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[String]
|
||||
$Path,
|
||||
|
||||
[String]
|
||||
$StringParam,
|
||||
|
||||
[UInt32]
|
||||
$UInt32Param,
|
||||
|
||||
[UInt64]
|
||||
$UInt64Param,
|
||||
|
||||
[String[]]
|
||||
$StringArrayParam,
|
||||
|
||||
[UInt32[]]
|
||||
$UInt32ArrayParam,
|
||||
|
||||
[UInt64[]]
|
||||
$UInt64ArrayParam,
|
||||
|
||||
[Boolean]
|
||||
$BooleanParam,
|
||||
|
||||
[PSCredential]
|
||||
$PSCredentialParam,
|
||||
|
||||
[Microsoft.Management.Infrastructure.CimInstance]
|
||||
$CimInstanceParam,
|
||||
|
||||
[Microsoft.Management.Infrastructure.CimInstance[]]
|
||||
$CimInstanceArrayParam
|
||||
)
|
||||
return $false
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function *-TargetResource
|
|
@ -0,0 +1,25 @@
|
|||
[ClassVersion("{{item.version}}")]
|
||||
class ANSIBLE_xTestClass
|
||||
{
|
||||
[Write] String StringKey;
|
||||
[Write] Boolean BooleanKey;
|
||||
[Write] UInt32 UInt32Key;
|
||||
[Write] String StringArrayKey[];
|
||||
};
|
||||
|
||||
[ClassVersion("{{item.version}}"), FriendlyName("xTestResource")]
|
||||
class ANSIBLE_xTestResource : OMI_BaseResource
|
||||
{
|
||||
[Key] String Path;
|
||||
[Required, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure;
|
||||
[Write] String StringParam;
|
||||
[Write] UInt32 UInt32Param;
|
||||
[Write] UInt64 UInt64Param;
|
||||
[Write] String StringArrayParam[];
|
||||
[Write] UInt32 UInt32ArrayParam[];
|
||||
[Write] UInt64 UInt64ArrayParam[];
|
||||
[Write] Boolean BooleanParam;
|
||||
[Write, EmbeddedInstance("MSFT_Credential")] String PSCredentialParam;
|
||||
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceParam;
|
||||
[Write, EmbeddedInstance("ANSIBLE_xTestClass")] String CimInstanceArrayParam[];
|
||||
};
|
12
test/integration/targets/win_dsc/templates/xTestDsc.psd1
Normal file
12
test/integration/targets/win_dsc/templates/xTestDsc.psd1
Normal file
|
@ -0,0 +1,12 @@
|
|||
@{
|
||||
ModuleVersion = '{{item.version}}'
|
||||
GUID = '{{item.version|to_uuid}}'
|
||||
Author = 'Ansible'
|
||||
CompanyName = 'Ansible'
|
||||
Copyright = '(c) 2017'
|
||||
Description = 'Test DSC Resource for Ansible integration tests'
|
||||
PowerShellVersion = '5.0'
|
||||
CLRVersion = '4.0'
|
||||
FunctionsToExport = '*'
|
||||
CmdletsToExport = '*'
|
||||
}
|
Loading…
Reference in a new issue