diff options
author | Jordan Borean <jborean93@gmail.com> | 2017-03-02 16:17:16 +1000 |
---|---|---|
committer | Matt Davis <nitzmahone@users.noreply.github.com> | 2017-03-01 22:17:16 -0800 |
commit | f4f09c9dbf9320d7d8f10b8c188d14b26486dcf8 (patch) | |
tree | 8a9085791093b4d36e75687e3a0290a59463e5fc | |
parent | 98b978d1d109be3375a808b9f0b9d359999e4654 (diff) | |
download | ansible-f4f09c9dbf9320d7d8f10b8c188d14b26486dcf8.tar.gz |
Rewrote win_service with more options/check_mode (#19143)
-rw-r--r-- | lib/ansible/modules/windows/win_service.ps1 | 449 | ||||
-rw-r--r-- | lib/ansible/modules/windows/win_service.py | 219 | ||||
-rw-r--r-- | test/integration/targets/win_service/defaults/main.yml | 9 | ||||
-rw-r--r-- | test/integration/targets/win_service/tasks/main.yml | 840 |
4 files changed, 1361 insertions, 156 deletions
diff --git a/lib/ansible/modules/windows/win_service.ps1 b/lib/ansible/modules/windows/win_service.ps1 index 4ea4e2697a..5f568d1bf7 100644 --- a/lib/ansible/modules/windows/win_service.ps1 +++ b/lib/ansible/modules/windows/win_service.ps1 @@ -19,87 +19,438 @@ # WANT_JSON # POWERSHELL_COMMON -$params = Parse-Args $args; +$ErrorActionPreference = "Stop" -$result = New-Object PSObject; -Set-Attr $result "changed" $false; +$params = Parse-Args $args -supports_check_mode $true +$check_mode = Get-AnsibleParam -obj $params "_ansible_check_mode" -type "bool" -default $false -$name = Get-Attr $params "name" -failifempty $true -$state = Get-Attr $params "state" $false -$startMode = Get-Attr $params "start_mode" $false +$dependencies = Get-AnsibleParam -obj $params -name 'dependencies' -failifempty $false -default $null +$dependency_action = Get-AnsibleParam -obj $params -name 'dependency_action' -failifempty $false -ValidateSet 'add', 'remove', 'set' -default 'set' +$description = Get-AnsibleParam -obj $params -name 'description' -failifempty $false -default $null +$desktop_interact = Get-AnsibleParam -obj $params -name 'desktop_interact' -type "bool" -failifempty $false -default $false +$display_name = Get-AnsibleParam -obj $params -name 'display_name' -failifempty $false -default $null +$name = Get-AnsibleParam -obj $params -name 'name' -failifempty $true +$password = Get-AnsibleParam -obj $params -name 'password' -failifempty $false -default $null +$path = Get-AnsibleParam -obj $params -name 'path' -failifempty $false -default $null +$start_mode = Get-AnsibleParam -obj $params -name 'start_mode' -failifempty $false -ValidateSet 'auto', 'manual', 'disabled', 'delayed' +$state = Get-AnsibleParam -obj $params -name 'state' -failifempty $false -ValidateSet 'started', 'stopped', 'restarted', 'absent' +$username = Get-AnsibleParam -obj $params -name 'username' -failifempty $false -default $null -If ($state) { - $state = $state.ToString().ToLower() - If (($state -ne 'started') -and ($state -ne 'stopped') -and ($state -ne 'restarted')) { - Fail-Json $result "state is '$state'; must be 'started', 'stopped', or 'restarted'" +$result = @{ + changed = $false + warnings = @() +} + +# Check if dependencies is a string and convert to a list +if ($dependencies -is [System.String]) { + $dependencies = @($dependencies) +} + +if ($username -ne $null -and $password -eq $null) { + Fail-Json $result "The argument 'password' must be supplied with 'username'" +} +if ($password -ne $null -and $username -eq $null) { + Fail-Json $result "The argument 'username' must be supplied with 'password'" +} +if ($desktop_interact -eq $true -and (-not ($username -eq "LocalSystem" -or $username -eq $null))) { + Fail-Json $result "Can only set 'desktop_interact' to true when 'username' equals 'LocalSystem'" +} + +Function Get-ServiceInfo($name) { + # Need to get new objects so we have the latest info + $svc = Get-Service -Name $name + $wmi_svc = Get-WmiObject Win32_Service | Where-Object { $_.Name -eq $svc.Name } + + # Delayed start_mode is in reality Automatic (Delayed), need to check reg key for type + $delayed = Get-DelayedStatus -name $svc.Name + $actual_start_mode = $wmi_svc.StartMode.ToString().ToLower() + if ($delayed -and $actual_start_mode -eq 'auto') { + $actual_start_mode = 'delayed' + } + + $existing_depenencies = @() + $existing_depended_by = @() + if ($svc.ServicesDependedOn.Count -gt 0) { + foreach ($dependency in $svc.ServicesDependedOn.Name) { + $existing_depenencies += $dependency + } } + if ($svc.DependentServices.Count -gt 0) { + foreach ($dependency in $svc.DependentServices.Name) { + $existing_depended_by += $dependency + } + } + + $result.exists = $true + $result.name = $svc.Name + $result.display_name = $svc.DisplayName + $result.state = $svc.Status.ToString().ToLower() + $result.start_mode = $actual_start_mode + $result.path = $wmi_svc.PathName + $result.description = $wmi_svc.Description + $result.username = $wmi_svc.startname + $result.desktop_interact = (ConvertTo-Bool $wmi_svc.DesktopInteract) + $result.dependencies = $existing_depenencies + $result.depended_by = $existing_depended_by } -If ($startMode) { - $startMode = $startMode.ToString().ToLower() - If (($startMode -ne 'auto') -and ($startMode -ne 'manual') -and ($startMode -ne 'disabled')) { - Fail-Json $result "start mode is '$startMode'; must be 'auto', 'manual', or 'disabled'" +Function Get-WmiErrorMessage($return_value) { + # These values are derived from https://msdn.microsoft.com/en-us/library/aa384901(v=vs.85).aspx + switch ($return_value) { + 1 { "Not Supported: The request is not supported" } + 2 { "Access Denied: The user did not have the necessary access" } + 3 { "Dependent Servies Running: The service cannot be stopped because other services that are running are dependent on it" } + 4 { "Invalid Service Control: Thre requested control code is not valid, or it is unacceptable to the service" } + 5 { "The requested control code cannot be sent to the service because the state of the service is equal to 0, 1, or 2" } + 6 { "Service Not Ative: The service has not been started" } + 7 { "Service Request Timeout: The service did not response to the start request in a timely fashion" } + 8 { "Unknown Failure: Unknown failure when starting the service" } + 9 { "Path Not Found: THe directory path to the service executable file was not found" } + 10 { "Service Already Running: The service is already running" } + 11 { "Service Database Locked: The database to add a new service is locked" } + 12 { "Service Dependency Deleted: A dependency this service relies on has been removed from the system" } + 13 { "Service Dependency Failure: The service failed to find the service needed from a dependent service" } + 14 { "Servoce Disabled: The service has been disbaled from the system" } + 15 { "Service Logon Failed: The service does not have the correct authentication to run on this system" } + 16 { "Service Marked For Deletion: This service is being removed from the system" } + 17 { "Service No Thread: The service has no execution thread" } + 18 { "Status Circular Dependecy: The service has circular dependencies when it starts" } + 19 { "Status Duplicate Name: A service is running under the same name" } + 20 { "Status Invalid Name: The service name has invalide characters" } + 21 { "Status Invalid Paramter: Invalid paramters have been passed to the service" } + 22 { "Status Invalid Service Account: The account under which this service runs is either invalid or lacks the permissions to run the service" } + 23 { "Status Service Exists: The service exists in the database of services available from the system" } + 24 { "Service Already Paused: The service is currently paused in the system" } + default { "Other Error" } } } -$svcName = $name -$svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue -If (-not $svc) { - Fail-Json $result "Service '$svcName' not installed" +Function Get-DelayedStatus($name) { + $delayed_key = "HKLM:\System\CurrentControlSet\Services\$name" + try { + $delayed = ConvertTo-Bool ((Get-ItemProperty -Path $delayed_key).DelayedAutostart) + } catch { + $delayed = $false + } + + $delayed } -# Use service name instead of display name for remaining actions. -If ($svcName -ne $svc.ServiceName) { - $svcName = $svc.ServiceName + +Function Set-ServiceStartMode($svc, $start_mode) { + if ($result.start_mode -ne $start_mode) { + try { + $delayed_key = "HKLM:\System\CurrentControlSet\Services\$($svc.Name)" + + if ($check_mode) { + # Original start up type was auto (delayed) and we want auto, need to removed delayed key + if ($start_mode -eq 'auto' -and $result.start_mode -eq 'delayed') { + Set-ItemProperty -Path $delayed_key -Name "DelayedAutostart" -Value 0 -Type DWORD -WhatIf + # Original start up type was auto and we want auto (delayed), need to add delayed key + } elseif ($start_mode -eq 'delayed' -and $result.start_mode -eq 'auto') { + Set-ItemProperty -Path $delayed_key -Name "DelayedAutostart" -Value 1 -Type DWORD -WhatIf + # Original start up type was not auto or auto (delayed), need to change to auto and add delayed key + } elseif ($start_mode -eq 'delayed') { + $svc | Set-Service -StartupType "auto" -WhatIf + Set-ItemProperty -Path $delayed_key -Name "DelayedAutostart" -Value 1 -Type DWORD -WhatIf + # Original start up type was not what we were looking for, just change to that type + } else { + $svc | Set-Service -StartupType $start_mode -WhatIf + } + } else { + if ($start_mode -eq 'auto' -and $result.start_mode -eq 'delayed') { + Set-ItemProperty -Path $delayed_key -Name "DelayedAutostart" -Value 0 -Type DWORD + } elseif ($start_mode -eq 'delayed' -and $result.start_mode -eq 'auto') { + Set-ItemProperty -Path $delayed_key -Name "DelayedAutostart" -Value 1 -Type DWORD + } elseif ($start_mode -eq 'delayed') { + $svc | Set-Service -StartupType "auto" + Set-ItemProperty -Path $delayed_key -Name "DelayedAutostart" -Value 1 -Type DWORD + } else { + $svc | Set-Service -StartupType $start_mode + } + } + } catch { + Fail-Json $result $_.Exception.Message + } + + $result.changed = $true + } } -Set-Attr $result "name" $svc.ServiceName -Set-Attr $result "display_name" $svc.DisplayName +Function Set-ServiceAccount($wmi_svc, $username, $password) { + if ($result.username -ne $username) { + #WMI.Change doesn't support -WhatIf, cannot fully test with check_mode + if (-not $check_mode) { + $return = $wmi_svc.Change($null,$null,$null,$null,$null,$false,$username,$password,$null,$null,$null) + if ($return.ReturnValue -ne 0) { + Fail-Json $result "$($return.ReturnValue): $(Get-WmiErrorMessage -return_value $return.ReturnValue)" + } + } -$svcMode = Get-WmiObject -Class Win32_Service -Property StartMode -Filter "Name='$svcName'" -If ($startMode) { - If ($svcMode.StartMode.ToLower() -ne $startMode) { - Set-Service -Name $svcName -StartupType $startMode - Set-Attr $result "changed" $true - Set-Attr $result "start_mode" $startMode + $result.changed = $true } - Else { - Set-Attr $result "start_mode" $svcMode.StartMode.ToLower() +} + +Function Set-ServiceDesktopInteract($wmi_svc, $desktop_interact) { + if ($result.desktop_interact -ne $desktop_interact) { + if (-not $check_mode) { + $return = $wmi_svc.Change($null,$null,$null,$null,$null,$desktop_interact,$null,$null,$null,$null,$null) + if ($return.ReturnValue -ne 0) { + Fail-Json $result "$($return.ReturnValue): $(Get-WmiErrorMessage -return_value $return.ReturnValue)" + } + } + + $result.changed = $true } } -Else { - Set-Attr $result "start_mode" $svcMode.StartMode.ToLower() + +Function Set-ServiceDisplayName($svc, $display_name) { + if ($result.display_name -ne $display_name) { + try { + if ($check_mode) { + $svc | Set-Service -DisplayName $display_name -WhatIf + } else { + $svc | Set-Service -DisplayName $display_name + } + } catch { + Fail-Json $result $_.Exception.Message + } + + $result.changed = $true + } } -If ($state) { - If ($state -eq "started" -and $svc.Status -ne "Running") { +Function Set-ServiceDescription($svc, $description) { + if ($result.description -ne $description) { try { - Start-Service -Name $svcName -ErrorAction Stop + if ($check_mode) { + $svc | Set-Service -Description $description -WhatIf + } else { + $svc | Set-Service -Description $description + } + } catch { + Fail-Json $result $_.Exception.Message } - catch { + + $result.changed = $true + } +} + +Function Set-ServicePath($name, $path) { + if ($result.path -ne $path) { + try { + if ($check_mode) { + Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\$name" -Name ImagePath -Value $path -WhatIf + } else { + Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\$name" -Name ImagePath -Value $path + } + } catch { Fail-Json $result $_.Exception.Message } - Set-Attr $result "changed" $true; + + $result.changed = $true + } +} + +Function Set-ServiceDependencies($wmi_svc, $dependency_action, $dependencies) { + $existing_dependencies = $result.dependencies + [System.Collections.ArrayList]$new_dependencies = @() + + if ($dependency_action -eq 'set') { + $new_dependencies = $dependencies + } else { + $new_dependencies = $existing_dependencies + foreach ($dependency in $dependencies) { + if ($dependency_action -eq 'remove') { + if ($new_dependencies -contains $dependency) { + $new_dependencies.Remove($dependency) + } + } elseif ($dependency_action -eq 'add') { + if ($new_dependencies -notcontains $dependency) { + $new_dependencies.Add($dependency) + } + } + } + } + + $will_change = $false + foreach ($dependency in $new_dependencies) { + if ($existing_dependencies -notcontains $dependency) { + $will_change = $true + } } - ElseIf ($state -eq "stopped" -and $svc.Status -ne "Stopped") { + foreach ($dependency in $existing_dependencies) { + if ($new_dependencies -notcontains $dependency) { + $will_change = $true + } + } + + if ($will_change -eq $true) { + if (-not $check_mode) { + $return = $wmi_svc.Change($null,$null,$null,$null,$null,$null,$null,$null,$null,$null,$new_dependencies) + if ($return.ReturnValue -ne 0) { + Fail-Json $result "$($return.ReturnValue): $(Get-WmiErrorMessage -return_value $return.ReturnValue)" + } + } + + $result.changed = $true + } +} + +Function Set-ServiceState($svc, $wmi_svc, $state) { + if ($state -eq "started" -and $result.state -ne "running") { try { - Stop-Service -Name $svcName -ErrorAction Stop + if ($check_mode) { + Start-Service -Name $svc.Name -WhatIf + } else { + Start-Service -Name $svc.Name + } + } catch { + Fail-Json $result $_.Exception.Message } - catch { + + $result.changed = $true + } + + if ($state -eq "stopped" -and $result.state -ne "stopped") { + try { + if ($check_mode) { + Stop-Service -Name $svc.Name -Force -WhatIf + } else { + Stop-Service -Name $svc.Name -Force + } + } catch { Fail-Json $result $_.Exception.Message } - Set-Attr $result "changed" $true; + + $result.changed = $true } - ElseIf ($state -eq "restarted") { + + if ($state -eq "restarted") { try { - Restart-Service -Name $svcName -ErrorAction Stop + if ($check_mode) { + Restart-Service -Name $svc.Name -Force -WhatIf + } else { + Restart-Service -Name $svc.Name -Force + } + } catch { + Fail-Json $result $_.Exception.Message } - catch { + + $result.changed = $true + } + + if ($state -eq "absent") { + try { + if ($check_mode) { + Stop-Service -Name $svc.Name -Force -WhatIf + } else { + Stop-Service -Name $svc.Name -Force + } + } catch { Fail-Json $result $_.Exception.Message } - Set-Attr $result "changed" $true; + if (-not $check_mode) { + $return = $wmi_svc.Delete() + if ($return.ReturnValue -ne 0) { + Fail-Json $result "$($return.ReturnValue): $(Get-WmiErrorMessage -return_value $return.ReturnValue)" + } + } + + $result.changed = $true + } +} + +Function Set-ServiceConfiguration($svc) { + $wmi_svc = Get-WmiObject Win32_Service | Where-Object { $_.Name -eq $svc.Name } + Get-ServiceInfo -name $svc.Name + if ($desktop_interact -eq $true -and (-not ($result.username -eq 'LocalSystem' -or $username -eq 'LocalSystem'))) { + Fail-Json $result "Can only set desktop_interact to true when service is run with or 'username' equals 'LocalSystem'" + } + + if ($start_mode -ne $null) { + Set-ServiceStartMode -svc $svc -start_mode $start_mode + } + + if ($username -ne $null) { + Set-ServiceAccount -wmi_svc $wmi_svc -username $username -password $password + } + + if ($display_name -ne $null) { + Set-ServiceDisplayName -svc $svc -display_name $display_name + } + + if ($desktop_interact -ne $null) { + Set-ServiceDesktopInteract -wmi_svc $wmi_svc -desktop_interact $desktop_interact + } + + if ($description -ne $null) { + Set-ServiceDescription -svc $svc -description $description + } + + if ($path -ne $null) { + Set-ServicePath -name $svc.Name -path $path + } + + if ($dependencies -ne $null) { + Set-ServiceDependencies -wmi_svc $wmi_svc -dependency_action $dependency_action -dependencies $dependencies + } + + if ($state -ne $null) { + Set-ServiceState -svc $svc -wmi_svc $wmi_svc -state $state + } +} + +$svc = Get-Service -Name $name -ErrorAction SilentlyContinue +if ($svc) { + Set-ServiceConfiguration -svc $svc +} else { + $result.exists = $false + if ($state -ne 'absent') { + # Check if path is defined, if so create the service + if ($path -ne $null) { + try { + if ($check_mode) { + New-Service -Name $name -BinaryPathname $path -WhatIf + } else { + New-Service -Name $name -BinaryPathname $path + } + } catch { + Fail-Json $result $_.Exception.Message + } + $result.changed = $true + + $svc = Get-Service -Name $name + Set-ServiceConfiguration -svc $svc + } else { + # We will only reach here if the service is installed and the state is not absent + # Will check if any of the default actions are set and fail as we cannot action it + if ($start_mode -ne $null -or + $state -ne $null -or + $username -ne $null -or + $password -ne $null -or + $display_name -ne $null -or + $description -ne $null -or + $desktop_interact -ne $false -or + $dependencies -ne $null -or + $dependency_action -ne 'set') { + Fail-Json $result "Service '$name' is not installed, need to set 'path' to create a new service" + } + } + } +} + +# After making a change, let's get the service info again unless we deleted it +if ($state -eq 'absent') { + # Recreate result so it doesn't have the extra meta data now that is has been deleted + $changed = $result.changed + $warnings = $result.warnings + $result = @{ + changed = $changed + warnings = $warnings + exists = $false } +} elseif ($svc -ne $null) { + Get-ServiceInfo -name $name } -$svc.Refresh() -Set-Attr $result "state" $svc.Status.ToString().ToLower() -Exit-Json $result; +Exit-Json $result diff --git a/lib/ansible/modules/windows/win_service.py b/lib/ansible/modules/windows/win_service.py index 9cb33ba76c..2eb91d20c6 100644 --- a/lib/ansible/modules/windows/win_service.py +++ b/lib/ansible/modules/windows/win_service.py @@ -33,32 +33,91 @@ short_description: Manages Windows services description: - Manages Windows services options: + dependencies: + description: + - A list of service dependencies to set for this particular service. + - This should be a list of service names and not the display name of the + service. + - This works by C(dependency_action) to either add/remove or set the + services in this list. + required: False + version_added: "2.3" + dependency_action: + description: + - Used in conjunction with C(dependency) to either add the dependencies to + the existing service dependencies. + - Remove the dependencies to the existing dependencies. + - Set the dependencies to only the values in the list replacing the + existing dependencies. + required: False + default: set + choices: + - set + - add + - remove + version_added: "2.3" + desktop_interact: + description: + - Whether to allow the service user to interact with the desktop. + - This should only be set to true when using the LocalSystem username. + required: False + default: False + version_added: "2.3" + description: + description: + - The description to set for the service. + required: False + version_added: "2.3" + display_name: + description: + - The display name to set for the service. + required: False + version_added: "2.3" name: description: - Name of the service required: true - default: null - aliases: [] + path: + description: + - The path to the executable to set for the service. + required: False + version_added: "2.3" + password: + description: + - The password to set the service to start as. + - This and the C(username) argument must be supplied together. + - If specifying LocalSystem, NetworkService or LocalService this field + must be an empty string and not null. + required: False + version_added: "2.3" start_mode: description: - - Set the startup type for the service + - Set the startup type for the service. + - C(delayed) added in Ansible 2.3 required: false choices: - auto - manual - disabled + - delayed state: description: - - C(started)/C(stopped) are idempotent actions that will not run - commands unless necessary. C(restarted) will always bounce the - service. + - C(started)/C(stopped)/C(absent) are idempotent actions that will not run + commands unless necessary. + - C(restarted) will always bounce the service. + - C(absent) added in Ansible 2.3 required: false choices: - started - stopped - restarted - default: null - aliases: [] + - absent + username: + description: + - The username to set the service to start as. + - This and the C(password) argument must be supplied together. + required: False + version_added: "2.3" author: "Chris Hoffman (@chrishoffman)" ''' @@ -73,4 +132,148 @@ EXAMPLES = r''' name: spooler start_mode: auto state: started + +# a new service will also default to the following values: +# - username: LocalSystem +# - state: stopped +# - start_mode: auto +- name: create a new service + win_service: + name: service name + path: C:\temp\test.exe + +- name: create a new service with extra details + win_service: + name: service name + path: C:\temp\test.exe + display_name: Service Name + description: A test service description + +- name: remove a service + win_service: + name: service name + state: absent + +- name: check if a service is installed + win_service: + name: service name + register: service_info + +- name: set the log on user to a domain account + win_service: + name: service name + state: restarted + username: DOMAIN\User + password: Password + +- name: set the log on user to a local account + win_service: + name: service name + state: restarted + username: .\Administrator + password: Password + +- name: set the log on user to Local System + win_service: + name: service name + state: restarted + username: LocalSystem + password: "" + +- name: set the log on user to Local System and allow it to interact with the desktop + win_service: + name: service name + state: restarted + username: LocalSystem + password: "" + desktop_interact: True + +- name: set the log on user to Network Service + win_service: + name: service name + state: restarted + username: NT AUTHORITY\NetworkService + password: "" + +- name: set the log on user to Local Service + win_service: + name: service name + state: restarted + username: NT AUTHORITY\LocalService + password: "" + +- name: set dependencies to ones only in the list + win_service: + name: service name + dependencies: ['service1', 'service2'] + +- name: add dependencies to existing dependencies + win_service: + name: service name + dependencies: ['service1', 'service2'] + dependency_action: add + +- name: remove dependencies from existing dependencies + win_service: + name: service name + dependencies: ['service1', 'service2'] + dependency_action: remove +''' + +RETURN = r''' +exists: + description: whether the service exists or not + returned: success + type: boolean + sample: true +name: + description: the service name or id of the service + returned: success and service exists + type: string + sample: CoreMessagingRegistrar +display_name: + description: the display name of the installed service + returned: success and service exists + type: string + sample: CoreMessaging +status: + description: the current running status of the service + returned: success and service exists + type: string + sample: stopped +start_mode: + description: the startup type of the service + returned: success and service exists + type: string + sample: manual +path: + description: + returned: success and service exists + type: string + sample: C:\Windows\system32\svchost.exe -k LocalServiceNoNetwork +description: + description: the path to the executable of the service + returned: success and service exists + type: string + sample: Manages communication between system components. +username: + description: the username that runs the service + returned: success and service exists + type: string + sample: LocalSystem +desktop_interact: + description: Whether the current user is allowed to interact with the desktop + returned: success and service exists + type: boolean + sample: False +dependencies: + description: A list of dependencies the service relies on + returned: success and service exists + type: List + sample: False +depended_by: + description: A list of dependencies this service relies on + returned: success and service exists + type: List + sample: False ''' diff --git a/test/integration/targets/win_service/defaults/main.yml b/test/integration/targets/win_service/defaults/main.yml index 1f38717aa4..4d4d0eca6b 100644 --- a/test/integration/targets/win_service/defaults/main.yml +++ b/test/integration/targets/win_service/defaults/main.yml @@ -1,5 +1,6 @@ --- - -# Service is commonly available and usually disabled/stopped by default. -test_win_service_name: SSDPSRV -test_win_service_display_name: "SSDP Discovery" +# parameters set here for creating new service in tests +test_win_service_name: TestService +test_win_service_display_name: Test Service +test_win_service_description: Test Service description +test_win_service_path: C:\Windows\System32\snmptrap.exe diff --git a/test/integration/targets/win_service/tasks/main.yml b/test/integration/targets/win_service/tasks/main.yml index 39562c4dcf..51f0cb50e5 100644 --- a/test/integration/targets/win_service/tasks/main.yml +++ b/test/integration/targets/win_service/tasks/main.yml @@ -16,181 +16,831 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see <http://www.gnu.org/licenses/>. +- name: remove the dummy test services if it is left over from previous tests + win_service: + name: "{{item}}" + state: absent + with_items: + - "{{test_win_service_name}}" + - TestServiceParent2 + - TestServiceDependency + +- name: create new dummy test service + win_service: + name: "{{test_win_service_name}}" + path: "{{test_win_service_path}}" + display_name: "{{test_win_service_display_name}}" + description: "{{test_win_service_description}}" + register: win_service_added + +- name: check that creating a new service succeeds with a change + assert: + that: + - "win_service_added|changed" + - "win_service_added.name == test_win_service_name" + - "win_service_added.display_name == test_win_service_display_name" + - "win_service_added.description == test_win_service_description" + - "win_service_added.path == test_win_service_path" + - "win_service_added.state == 'stopped'" + - "win_service_added.start_mode == 'auto'" + - "win_service_added.username == 'LocalSystem'" + - "win_service_added.desktop_interact == False" + - "win_service_added.dependencies == []" + - "win_service_added.depended_by == []" + - "win_service_added.exists == True" + - name: test win_service module with short name - win_service: name="{{ test_win_service_name }}" + win_service: + name: "{{test_win_service_name}}" register: win_service_name - name: check win_service result with short name assert: that: - - "not win_service_name|changed" - - "win_service_name.name" - - "win_service_name.display_name" - - "win_service_name.start_mode" - - "win_service_name.state" + - "not win_service_name|changed" + - "win_service_name.name == test_win_service_name" + - "win_service_name.display_name == test_win_service_display_name" + - "win_service_name.start_mode == 'auto'" + - "win_service_name.state == 'stopped'" + - "win_service_name.description == test_win_service_description" + - "win_service_name.exists == True" + - "win_service_name.path == test_win_service_path" + - "win_service_name.username == 'LocalSystem'" + - "win_service_name.desktop_interact == False" + - "win_service_name.dependencies == []" + - "win_service_name.depended_by == []" - name: test win_service module with display name - win_service: name="{{ test_win_service_display_name }}" + win_service: + name: "{{test_win_service_display_name}}" register: win_service_display_name - name: check win_service result with display name assert: that: - - "not win_service_display_name|changed" - - "win_service_display_name.name" - - "win_service_display_name.display_name" - - "win_service_display_name.start_mode" - - "win_service_display_name.state" + - "not win_service_display_name|changed" + - "win_service_display_name.name == test_win_service_name" + - "win_service_display_name.display_name == test_win_service_display_name" + - "win_service_display_name.start_mode == 'auto'" + - "win_service_display_name.state == 'stopped'" + - "win_service_display_name.description == test_win_service_description" + - "win_service_display_name.exists == True" + - "win_service_display_name.path == test_win_service_path" + - "win_service_display_name.username == 'LocalSystem'" + - "win_service_display_name.desktop_interact == False" + - "win_service_display_name.dependencies == []" + - "win_service_display_name.depended_by == []" - name: test win_service module with invalid name - win_service: name="iamnotaservice" - ignore_errors: true + win_service: + name: iamnotaservice register: win_service_invalid -- name: check win_service result with invalid_name +- name: check win_service result with invalid name assert: that: - - "win_service_invalid|failed" - - "win_service_invalid.msg" + - "not win_service_invalid|changed" + - "win_service_invalid.exists == False" -- name: make sure the service is stopped and disabled - win_service: name="{{ test_win_service_name }}" state=stopped start_mode=disabled - register: win_service_stopped_disabled +- name: test win_service module with invalid name and absent state + win_service: + name: iamnotaservice + state: absent + register: win_service_invalid_with_absent -- name: check result of disabling and stopping the service +- name: check win_service result with invalid name and absent state assert: that: - - "win_service_stopped_disabled.start_mode == 'disabled'" - - "win_service_stopped_disabled.state == 'stopped'" + - "not win_service_invalid_with_absent|changed" + - "win_service_invalid_with_absent.exists == False" + +- name: test win_service module with invalid name and startup + win_service: + name: iamnotaservice + state: started + register: win_service_invalid_with_action + ignore_errors: True + +- name: check win_service result with invalid name and startup + assert: + that: + - "win_service_invalid_with_action|failed" + - "win_service_invalid_with_action.msg == 'Service \\'iamnotaservice\\' is not installed, need to set \\'path\\' to create a new service'" + +- name: make sure the service is stopped and disabled for next tests + win_service: + name: "{{test_win_service_name}}" + state: stopped + start_mode: disabled + register: win_service_stopped_disabled - name: try to start the disabled service - win_service: name="{{ test_win_service_name }}" state=started + win_service: + name: "{{test_win_service_name}}" + state: started register: win_service_start_disabled - ignore_errors: true + ignore_errors: True -- name: check that starting the disabled service fails +- name: check that trying to start a disabled service failed assert: that: - - "win_service_start_disabled|failed" - - "win_service_start_disabled.msg" + - "win_service_start_disabled|failed" + - "win_service_start_disabled.msg" - name: enable the service for manual startup - win_service: name="{{ test_win_service_name }}" start_mode=manual + win_service: + name: "{{test_win_service_name}}" + start_mode: manual register: win_service_manual_start_mode -- name: check that enabling the service succeeds for manual startup +- name: check that enabling the service for manual startup succeeded assert: that: - - "win_service_manual_start_mode|changed" - - "win_service_manual_start_mode.start_mode == 'manual'" - - "win_service_manual_start_mode.state == 'stopped'" - -- name: enable the service again for manual startup - win_service: name="{{ test_win_service_name }}" start_mode=manual + - "win_service_manual_start_mode|changed" + - "win_service_manual_start_mode.start_mode == 'manual'" + - "win_service_manual_start_mode.state == 'stopped'" + +- name: enable the service for manual startup again + win_service: + name: "{{test_win_service_name}}" + start_mode: manual register: win_service_manual_start_mode_again -- name: check that enabling the service succeeds for manual startup +- name: check that enabling service for manual startup again didn't change anything assert: that: - - "not win_service_manual_start_mode_again|changed" - - "win_service_manual_start_mode_again.start_mode == 'manual'" - - "win_service_manual_start_mode_again.state == 'stopped'" + - "not win_service_manual_start_mode_again|changed" + - "win_service_manual_start_mode_again.start_mode == 'manual'" + - "win_service_manual_start_mode_again.state == 'stopped'" -- name: try to start the manual service - win_service: name="{{ test_win_service_name }}" state=started - register: win_service_start_manual +- name: enable the service for delayed startup from non automatic + win_service: + name: "{{test_win_service_name}}" + start_mode: delayed + register: win_service_delayed_start_mode -- name: check that starting the manual service succeeds +- name: check that that enabling the service for delayed startup succeeded assert: that: - - "win_service_start_manual|changed" - - "win_service_start_manual.start_mode == 'manual'" - - "win_service_start_manual.state == 'running'" + - "win_service_delayed_start_mode|changed" + - "win_service_delayed_start_mode.start_mode == 'delayed'" + - "win_service_delayed_start_mode.state == 'stopped'" -- name: try to start the manual service again - win_service: name="{{ test_win_service_name }}" state=started - register: win_service_start_manual_again +- name: enable the service for delayed startup from non automatic again + win_service: + name: "{{test_win_service_name}}" + start_mode: delayed + register: win_service_delayed_start_mode_again -- name: check that starting the manual service again succeeds without changes +- name: check that enabling the service for delayed startup again no changes assert: that: - - "not win_service_start_manual_again|changed" - - "win_service_start_manual_again.start_mode == 'manual'" - - "win_service_start_manual_again.state == 'running'" + - "not win_service_delayed_start_mode_again|changed" + - "win_service_delayed_start_mode_again.start_mode == 'delayed'" + - "win_service_delayed_start_mode_again.state == 'stopped'" - name: enable the service for automatic startup - win_service: name="{{ test_win_service_name }}" start_mode=auto + win_service: + name: "{{test_win_service_name}}" + start_mode: auto register: win_service_auto_start_mode -- name: check that enabling the service succeeds for automatic startup +- name: check that enabling the service for auto startup succeeded assert: that: - - "win_service_auto_start_mode|changed" - - "win_service_auto_start_mode.start_mode == 'auto'" - - "win_service_auto_start_mode.state == 'running'" - -- name: enable the service again for automatic startup - win_service: name="{{ test_win_service_name }}" start_mode=auto + - "win_service_auto_start_mode|changed" + - "win_service_auto_start_mode.start_mode == 'auto'" + - "win_service_auto_start_mode.state == 'stopped'" + +- name: enable the service for automatic startup again + win_service: + name: "{{test_win_service_name}}" + start_mode: auto register: win_service_auto_start_mode_again -- name: check that enabling the service succeeds for automatic startup without changes +- name: check that enabling the service for auto startup again no changes assert: that: - - "not win_service_auto_start_mode_again|changed" - - "win_service_auto_start_mode_again.start_mode == 'auto'" - - "win_service_auto_start_mode_again.state == 'running'" + - "not win_service_auto_start_mode_again|changed" + - "win_service_auto_start_mode_again.start_mode == 'auto'" + - "win_service_auto_start_mode_again.state == 'stopped'" + +- name: enable the service for delayed startup from automatic + win_service: + name: "{{test_win_service_name}}" + start_mode: delayed + register: win_service_delayed_start_mode_from_auto + +- name: check that enabling the service for delayed startup from auto succeeded + assert: + that: + - "win_service_delayed_start_mode_from_auto|changed" + - "win_service_delayed_start_mode_from_auto.start_mode == 'delayed'" + - "win_service_delayed_start_mode_from_auto.state == 'stopped'" + +- name: enable the service for delayed startup from automatic again + win_service: + name: "{{test_win_service_name}}" + start_mode: delayed + register: win_service_delayed_start_mode_from_auto_again + +- name: check that enabling the service for delayed startup from auto succeeded again no change + assert: + that: + - "not win_service_delayed_start_mode_from_auto_again|changed" + - "win_service_delayed_start_mode_from_auto_again.start_mode == 'delayed'" + - "win_service_delayed_start_mode_from_auto_again.state == 'stopped'" + +- name: start the service + win_service: + name: "{{test_win_service_name}}" + state: started + register: win_service_start + +- name: check that starting the service succeeds with changes + assert: + that: + - "win_service_start|changed" + - "win_service_start.state == 'running'" + +- name: start the service again + win_service: + name: "{{test_win_service_name}}" + state: started + register: win_service_start_again + +- name: check that starting the service succeeds again with no changes + assert: + that: + - "not win_service_start_again|changed" + - "win_service_start_again.state == 'running'" + - name: restart the service - win_service: name="{{ test_win_service_name }}" state=restarted - register: win_service_restart_auto + win_service: + name: "{{test_win_service_name}}" + state: restarted + register: win_service_restart - name: check that restarting the service succeeds with changes assert: that: - - "win_service_restart_auto|changed" - - "win_service_restart_auto.start_mode == 'auto'" - - "win_service_restart_auto.state == 'running'" + - "win_service_restart|changed" + - "win_service_restart.state =='running'" + +- name: restart the service again + win_service: + name: "{{test_win_service_name}}" + state: restarted + register: win_service_restart_again + +- name: check that restarting the service again succeeds with changes + assert: + that: + - "win_service_restart_again|changed" + - "win_service_restart_again.state =='running'" -- name: disable the service again - win_service: name="{{ test_win_service_name }}" start_mode=disabled - register: win_service_disabled_start_mode +- name: disable the service while running + win_service: + name: "{{test_win_service_name}}" + start_mode: disabled + register: win_service_disabled_while_running - name: check that disabling the service succeeds, service is still running assert: that: - - "win_service_disabled_start_mode|changed" - - "win_service_disabled_start_mode.start_mode == 'disabled'" - - "win_service_disabled_start_mode.state == 'running'" + - "win_service_disabled_while_running|changed" + - "win_service_disabled_while_running.start_mode == 'disabled'" + - "win_service_disabled_while_running.state == 'running'" -- name: disable the service again - win_service: name="{{ test_win_service_name }}" start_mode=disabled - register: win_service_disabled_start_mode_again +- name: disable the service while running again + win_service: + name: "{{test_win_service_name}}" + start_mode: disabled + register: win_service_disabled_while_running_again -- name: check that disabling the service succeeds again +- name: check that disabling the service again succeeds, service is still running but with no changes assert: that: - - "not win_service_disabled_start_mode_again|changed" - - "win_service_disabled_start_mode_again.start_mode == 'disabled'" - - "win_service_disabled_start_mode_again.state == 'running'" + - "not win_service_disabled_while_running_again|changed" + - "win_service_disabled_while_running_again.start_mode == 'disabled'" + - "win_service_disabled_while_running_again.state == 'running'" - name: stop the service - win_service: name="{{ test_win_service_name }}" state=stopped - register: win_service_stop_disabled + win_service: + name: "{{test_win_service_name}}" + state: stopped + register: win_service_stopped - name: check that stopping the service succeeds with changes assert: that: - - "win_service_stop_disabled|changed" - - "win_service_stop_disabled.start_mode == 'disabled'" - - "win_service_stop_disabled.state == 'stopped'" + - "win_service_stopped|changed" + - "win_service_stopped.state == 'stopped'" - name: stop the service again - win_service: name="{{ test_win_service_name }}" state=stopped - register: win_service_stop_disabled_again + win_service: + name: "{{test_win_service_name}}" + state: stopped + register: win_service_stopped_again + +- name: check that stopping the service again succeeds with no changes + assert: + that: + - "not win_service_stopped_again|changed" + - "win_service_stopped_again.state == 'stopped'" + +- name: set username without password + win_service: + name: "{{test_win_service_name}}" + username: username + register: win_service_change_user_without_password + ignore_errors: True + +- name: check that setting a user without a password fails + assert: + that: + - "win_service_change_user_without_password|failed" + - "win_service_change_user_without_password.msg" + +- name: set password without username + win_service: + name: "{{test_win_service_name}}" + password: password + register: win_service_change_password_without_user + ignore_errors: True + +- name: check that setting a user without a password fails + assert: + that: + - "win_service_change_password_without_user|failed" + - "win_service_change_password_without_user.msg" + +- name: set service username to Network Service and desktop interact fail + win_service: + name: "{{test_win_service_name}}" + username: NT AUTHORITY\NetworkService + password: "" + desktop_interact: True + register: win_desktop_interact_not_local_system + ignore_errors: True + +- name: check that setting desktop interact with non LocalSystem failed + assert: + that: + - "win_desktop_interact_not_local_system|failed" + - "win_desktop_interact_not_local_system.msg" + +- name: set service username to Network Service + win_service: + name: "{{test_win_service_name}}" + username: NT AUTHORITY\NetworkService + password: "" + register: win_service_change_password_network_service + +- name: check that the service user has been set to Network Service + assert: + that: + - "win_service_change_password_network_service|changed" + - "win_service_change_password_network_service.username == 'NT AUTHORITY\\\\NetworkService'" + - "win_service_change_password_network_service.desktop_interact == False" + +- name: set service username to Network Service again + win_service: + name: "{{test_win_service_name}}" + username: NT AUTHORITY\NetworkService + password: "" + register: win_service_change_password_network_service_again + +- name: check that the service user has been set to Network Service and nothing changed + assert: + that: + - "not win_service_change_password_network_service_again|changed" + - "win_service_change_password_network_service_again.username == 'NT AUTHORITY\\\\NetworkService'" + - "win_service_change_password_network_service_again.desktop_interact == False" + +- name: set service username to interact with desktop with existing user to fail + win_service: + name: "{{test_win_service_name}}" + desktop_interact: True + register: win_service_desktop_interact_current_user_fail + ignore_errors: True + +- name: check that setting desktop interact with current user not LocalSystem failed + assert: + that: + - "win_service_desktop_interact_current_user_fail|failed" + - "win_service_desktop_interact_current_user_fail.msg" + +- name: set service username to Local Service + win_service: + name: "{{test_win_service_name}}" + username: NT AUTHORITY\LocalService + password: "" + register: win_service_change_password_local_service + +- name: check that the service user has been set to Local Service + assert: + that: + - "win_service_change_password_local_service|changed" + - "win_service_change_password_local_service.username == 'NT AUTHORITY\\\\LocalService'" + - "win_service_change_password_local_service.desktop_interact == False" + +- name: set service username to Local Service again + win_service: + name: "{{test_win_service_name}}" + username: NT AUTHORITY\LocalService + password: "" + register: win_service_change_password_local_service_again + +- name: check that the service user has been set to Local Service and nothing changed + assert: + that: + - "not win_service_change_password_local_service_again|changed" + - "win_service_change_password_local_service_again.username == 'NT AUTHORITY\\\\LocalService'" + - "win_service_change_password_local_service_again.desktop_interact == False" + +- name: set service username to Local System + win_service: + name: "{{test_win_service_name}}" + username: LocalSystem + password: "" + register: win_service_change_password_local_system + +- name: check that the service user has been set to Local System + assert: + that: + - "win_service_change_password_local_system|changed" + - "win_service_change_password_local_system.username == 'LocalSystem'" + - "win_service_change_password_local_system.desktop_interact == False" + +- name: set service username to Local System again + win_service: + name: "{{test_win_service_name}}" + username: LocalSystem + password: "" + register: win_service_change_password_local_system_again + +- name: check that the service user has been set to Local System and nothing changed + assert: + that: + - "not win_service_change_password_local_system_again|changed" + - "win_service_change_password_local_system_again.username == 'LocalSystem'" + - "win_service_change_password_local_system_again.desktop_interact == False" + +- name: set service username to Local System with desktop interaction + win_service: + name: "{{test_win_service_name}}" + username: LocalSystem + password: "" + desktop_interact: True + register: win_service_local_system_desktop + +- name: check that the service has been set to Local Sytem with desktop interaction + assert: + that: + - "win_service_local_system_desktop|changed" + - "win_service_local_system_desktop.username == 'LocalSystem'" + - "win_service_local_system_desktop.desktop_interact == True" + +- name: set service username to Local System with desktop interaction again + win_service: + name: "{{test_win_service_name}}" + username: LocalSystem + password: "" + desktop_interact: True + register: win_service_local_system_desktop_again + +- name: check that the service has been set to Local System with desktop interaction again + assert: + that: + - "not win_service_local_system_desktop_again|changed" + - "win_service_local_system_desktop_again.username == 'LocalSystem'" + - "win_service_local_system_desktop_again.desktop_interact == True" + +- name: set desktop interaction to disabled + win_service: + name: "{{test_win_service_name}}" + desktop_interact: False + register: win_service_desktop_disable + +- name: check that desktop interaction has been disabled + assert: + that: + - "win_service_desktop_disable|changed" + - "win_service_desktop_disable.username == 'LocalSystem'" + - "win_service_desktop_disable.desktop_interact == False" + +- name: set desktop interaction to disabled again + win_service: + name: "{{test_win_service_name}}" + desktop_interact: False + register: win_service_desktop_disable_again + +- name: check that desktop interaction has been disabled again + assert: + that: + - "not win_service_desktop_disable_again|changed" + - "win_service_desktop_disable_again.username == 'LocalSystem'" + - "win_service_desktop_disable_again.desktop_interact == False" + +- name: set desktop interaction to enabled with current user as LocalSystem + win_service: + name: "{{test_win_service_name}}" + desktop_interact: True + register: win_service_desktop_enable + +- name: check that desktop iteraction has been enabled + assert: + that: + - "win_service_desktop_enable|changed" + - "win_service_desktop_enable.username == 'LocalSystem'" + - "win_service_desktop_enable.desktop_interact == True" + +- name: set desktop interaction to enabled with current user as LocalSystem again + win_service: + name: "{{test_win_service_name}}" + desktop_interact: True + register: win_service_desktop_enable_again + +- name: check that desktop iteraction has been enabled again + assert: + that: + - "not win_service_desktop_enable_again|changed" + - "win_service_desktop_enable_again.username == 'LocalSystem'" + - "win_service_desktop_enable_again.desktop_interact == True" + +- name: set service username to current user + win_service: + name: "{{test_win_service_name}}" + username: ".\\{{ansible_user}}" + password: "{{ansible_password}}" + register: win_service_change_password_current_user + +- name: check that the service user has been set to current user + assert: + that: + - "win_service_change_password_current_user|changed" + - "win_service_change_password_current_user.username == '.\\\\{{ansible_user}}'" + - "win_service_change_password_current_user.desktop_interact == False" + +- name: set service username to current user again + win_service: + name: "{{test_win_service_name}}" + username: ".\\{{ansible_user}}" + password: "{{ansible_password}}" + register: win_service_change_password_current_user_again + +- name: check that the service user has been set to current user and nothing changed + assert: + that: + - "not win_service_change_password_current_user_again|changed" + - "win_service_change_password_current_user_again.username == '.\\\\{{ansible_user}}'" + - "win_service_change_password_current_user_again.desktop_interact == False" + +- name: set service display name + win_service: + name: "{{test_win_service_name}}" + display_name: Test Service New + register: win_service_display_name + +- name: check that the service display name has been changed + assert: + that: + - "win_service_display_name|changed" + - "win_service_display_name.display_name == 'Test Service New'" + +- name: set service display name again + win_service: + name: "{{test_win_service_name}}" + display_name: Test Service New + register: win_service_display_name_again + +- name: check that the service display name has been changed again + assert: + that: + - "not win_service_display_name_again|changed" + - "win_service_display_name_again.display_name == 'Test Service New'" + +- name: set service description + win_service: + name: "{{test_win_service_name}}" + description: New Description + register: win_service_description + +- name: check that the service description has been changed + assert: + that: + - "win_service_description|changed" + - "win_service_description.description == 'New Description'" + +- name: set service description again + win_service: + name: "{{test_win_service_name}}" + description: New Description + register: win_service_description_again + +- name: check that the service description has been changed again + assert: + that: + - "not win_service_description_again|changed" + - "win_service_description_again.description == 'New Description'" + +- name: set service path + win_service: + name: "{{test_win_service_name}}" + path: C:\temp\test.exe + register: win_service_path -- name: check that stopping the service again succeeds without changes +- name: check that the service path has been changed + assert: + that: + - "win_service_path|changed" + - "win_service_path.path == 'C:\\\\temp\\\\test.exe'" + +- name: set service path again + win_service: + name: "{{test_win_service_name}}" + path: C:\temp\test.exe + register: win_service_path_again + +- name: check that the service path has been changed again + assert: + that: + - "not win_service_path_again|changed" + - "win_service_path_again.path == 'C:\\\\temp\\\\test.exe'" + +- name: revert original service path back to normal + win_service: + name: "{{test_win_service_name}}" + path: "{{test_win_service_path}}" + +- name: create new second dependency parent service + win_service: + name: TestServiceParent2 + display_name: Test Service Parent 2 + path: "{{test_win_service_path}}" + +- name: create new dependency service + win_service: + name: TestServiceDependency + display_name: Test Service Dependency + path: "{{test_win_service_path}}" + dependencies: "{{test_win_service_name}}" + register: win_service_dependency_string + +- name: check that the service with a dependency has been created + assert: + that: + - "win_service_dependency_string|changed" + - "win_service_dependency_string.dependencies == ['{{test_win_service_name}}']" + +- name: create new dependencys service again + win_service: + name: TestServiceDependency + dependencies: "{{test_win_service_name}}" + register: win_service_dependency_string_again + +- name: check that the service with a dependency has been created again + assert: + that: + - "not win_service_dependency_string_again|changed" + - "win_service_dependency_string_again.dependencies == ['{{test_win_service_name}}']" + +- name: add another dependency to service + win_service: + name: TestServiceDependency + dependencies: ['TestServiceParent2'] + dependency_action: add + register: win_service_dependency_add + +- name: check that the service with a dependency has been added + assert: + that: + - "win_service_dependency_add|changed" + - "win_service_dependency_add.dependencies == ['{{test_win_service_name}}', 'TestServiceParent2']" + +- name: add another dependency to service again + win_service: + name: TestServiceDependency + dependencies: ['TestServiceParent2'] + dependency_action: add + register: win_service_dependency_add_again + +- name: check that the service with a dependency has been added again + assert: + that: + - "not win_service_dependency_add_again|changed" + - "win_service_dependency_add_again.dependencies == ['{{test_win_service_name}}', 'TestServiceParent2']" + +- name: remove another dependency to service + win_service: + name: TestServiceDependency + dependencies: ['TestServiceParent2'] + dependency_action: remove + register: win_service_dependency_add + +- name: check that the service with a dependency has been remove + assert: + that: + - "win_service_dependency_add|changed" + - "win_service_dependency_add.dependencies == ['{{test_win_service_name}}']" + +- name: remove another dependency to service again + win_service: + name: TestServiceDependency + dependencies: ['TestServiceParent2'] + dependency_action: remove + register: win_service_dependency_add_again + +- name: check that the service with a dependency has been removed again + assert: + that: + - "not win_service_dependency_add_again|changed" + - "win_service_dependency_add_again.dependencies == ['{{test_win_service_name}}']" + +- name: set dependency with a list + win_service: + name: TestServiceDependency + dependencies: ['{{test_win_service_name}}', 'TestServiceParent2'] + dependency_action: set + register: win_service_dependency_set_list + +- name: check that the service with dependencies has been set + assert: + that: + - "win_service_dependency_set_list|changed" + - "win_service_dependency_set_list.dependencies == ['{{test_win_service_name}}', 'TestServiceParent2']" + +- name: make sure all services are stopped, set to LocalSystem and set to auto start before next test + win_service: + name: "{{item}}" + state: stopped + start_mode: auto + username: LocalSystem + password: "" + with_items: + - "{{test_win_service_name}}" + - TestServiceParent2 + - TestServiceDependency + +- name: start up dependency service + win_service: + name: TestServiceDependency + state: started + +- name: wait 5 seconds for service to propogate service startup + pause: + seconds: 5 + +- name: get stat of 1st parent service + win_service: + name: "{{test_win_service_name}}" + register: win_service_parent1_stat + +- name: get stat of 2nd parent service + win_service: + name: TestServiceParent2 + register: win_service_parent2_stat + +- name: get stat of dependent service + win_service: + name: TestServiceDependency + register: win_service_dependent_stat + +- name: check that the dependency services started correctly and have the correct stats + assert: + that: + - "win_service_parent1_stat.state == 'running'" + - "win_service_parent2_stat.state == 'running'" + - "win_service_dependent_stat.state == 'running'" + - "win_service_parent1_stat.depended_by == ['TestServiceDependency']" + - "win_service_parent2_stat.depended_by == ['TestServiceDependency']" + +- name: remove the service + win_service: + name: "{{test_win_service_name}}" + state: absent + register: win_service_removed + +- name: check that removing the service succeeds with changes assert: that: - - "not win_service_stop_disabled_again|changed" - - "win_service_stop_disabled_again.start_mode == 'disabled'" - - "win_service_stop_disabled_again.state == 'stopped'" + - "win_service_removed|changed" + - "win_service_removed.exists == False" + - "win_service_removed.description is not defined" + - "win_service_removed.display_name is not defined" + - "win_service_removed.name is not defined" + - "win_service_removed.path is not defined" + - "win_service_removed.start_mode is not defined" + - "win_service_removed.state is not defined" + - "win_service_removed.username is not defined" + +- name: make sure all services are removed in the end + win_service: + name: "{{item}}" + state: absent + with_items: + - "{{test_win_service_name}}" + - TestServiceParent2 + - TestServiceDependency |