From 61335a42c2856c72d3c2e76c5a1403233c96d62d Mon Sep 17 00:00:00 2001 From: nwsparks Date: Tue, 29 Aug 2017 16:22:06 -0400 Subject: [PATCH] added windows module win_power_plan with integration test (#27966) * added windows module win_power_plan with integration test integration testing updated to handle skipping 2008 while testing that module provides helpful error * minor docs fix * my fault, too many spaces --- .../modules/windows/win_power_plan.ps1 | 77 ++++++++++++++++++ lib/ansible/modules/windows/win_power_plan.py | 59 ++++++++++++++ .../targets/win_power_plan/aliases | 1 + .../targets/win_power_plan/tasks/main.yml | 78 +++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 lib/ansible/modules/windows/win_power_plan.ps1 create mode 100644 lib/ansible/modules/windows/win_power_plan.py create mode 100644 test/integration/targets/win_power_plan/aliases create mode 100644 test/integration/targets/win_power_plan/tasks/main.yml diff --git a/lib/ansible/modules/windows/win_power_plan.ps1 b/lib/ansible/modules/windows/win_power_plan.ps1 new file mode 100644 index 0000000000..5cd8daf8d0 --- /dev/null +++ b/lib/ansible/modules/windows/win_power_plan.ps1 @@ -0,0 +1,77 @@ +#!powershell + +# 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.psm1 + +$params = Parse-Args -arguments $args -supports_check_mode $true +$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false + +# these are your module parameters +$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true + +Function Get-PowerPlans { +Param ($PlanName) + If (!$PlanName) { + Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan | Select ElementName,IsActive | + Foreach -begin { $ht=@{} } -process { $ht."$($_.ElementName)" = $_.IsActive } -end {$ht} + } + Else { + Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan -Filter "ElementName = '$PlanName'" + } +} + +#fail if older than 2008r2...need to do it here before Get-PowerPlans function runs further down +If ( (gcim Win32_OperatingSystem).version -lt 6.1) +{ + $result = @{ + changed = $false + power_plan_name = $name + power_plan_enabled = $null + all_available_plans = $null + } + Fail-Json $result "The win_power_plan Ansible module is only available on Server 2008r2 (6.1) and newer" +} + +$result = @{ + changed = $false + power_plan_name = $name + power_plan_enabled = (Get-PowerPlans $name).isactive + all_available_plans = Get-PowerPlans +} + +$all_available_plans = Get-PowerPlans + +#Terminate if plan is not found on the system +If (! ($all_available_plans.ContainsKey($name)) ) +{ + Fail-Json $result "Defined power_plan: ($name) is not available" +} + +#If true, means plan is already active and we exit here with changed: false +#If false, means plan is not active and we move down to enable +#Since the results here are the same whether check mode or not, no specific handling is required +#for check mode. +If ( $all_available_plans.item($name) ) +{ + Exit-Json $result +} +Else +{ + Try { + $Null = Invoke-CimMethod -InputObject (Get-PowerPlans $name) -MethodName Activate -ea Stop -WhatIf:$check_mode + } + Catch { + $result.power_plan_enabled = (Get-PowerPlans $name).isactive + $result.all_available_plans = Get-PowerPlans + Fail-Json $result "Failed to set the new plan: $($_.Exception.Message)" + } + + #set success parameters and exit + $result.changed = $true + $result.power_plan_enabled = (Get-PowerPlans $name).isactive + $result.all_available_plans = Get-PowerPlans + Exit-Json $result +} + diff --git a/lib/ansible/modules/windows/win_power_plan.py b/lib/ansible/modules/windows/win_power_plan.py new file mode 100644 index 0000000000..d0e1d7bb6d --- /dev/null +++ b/lib/ansible/modules/windows/win_power_plan.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +# 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'], + 'supported_by': 'community'} + + +DOCUMENTATION = ''' +--- +module: win_power_plan +short_description: Changes the power plan of a Windows system +description: + - This module will change the power plan of a Windows system to the defined string. + - Windows defaults to C(balanced) which will cause CPU throttling. In some cases it can be preferable + to change the mode to C(high performance) to increase CPU performance. +version_added: "2.4" +author: + - Noah Sparks (@nwsparks) +options: + name: + description: + - String value that indicates the desired power plan. The power plan must already be + present on the system. Commonly there will be options for C(balanced) and C(high performance). + required: True +requirements: + - Windows Server 2008R2 (6.1)/Windows 7 or higher +''' + +EXAMPLES = ''' +- name: change power plan to high performance + win_power_plan: + name: high performance +''' + +RETURN = r''' +power_plan_name: + description: Value of the intended power plan + returned: always + type: string + sample: balanced +power_plan_enabled: + description: State of the intended power plan + returned: success + type: boolean + sample: True +all_available_plans: + description: The name and enabled state of all power plans + returned: always + type: dictionary + sample: | + { + "High performance": false, + "Balanced": true, + "Power saver": false + } +''' diff --git a/test/integration/targets/win_power_plan/aliases b/test/integration/targets/win_power_plan/aliases new file mode 100644 index 0000000000..1ab6431271 --- /dev/null +++ b/test/integration/targets/win_power_plan/aliases @@ -0,0 +1 @@ +windows/ci/group2 \ No newline at end of file diff --git a/test/integration/targets/win_power_plan/tasks/main.yml b/test/integration/targets/win_power_plan/tasks/main.yml new file mode 100644 index 0000000000..b88cd271fb --- /dev/null +++ b/test/integration/targets/win_power_plan/tasks/main.yml @@ -0,0 +1,78 @@ +- name: register os version (seems integration tests don't gather this fact) + raw: powershell.exe "gwmi Win32_OperatingSystem | select -expand version" + register: os_version + changed_when: False +# ^^ seems "raw" is the only module that works on 2008 non-r2. win_command and win_shell both failed + +- name: check if module fails gracefully when older than 2008r2 + win_power_plan: + name: "high performance" + when: os_version.stdout_lines[0] | version_compare('6.1','lt') + check_mode: yes + register: old_os_check + failed_when: old_os_check.msg != 'The win_power_plan Ansible module is only available on Server 2008r2 (6.1) and newer' + +- block: + - name: register inactive power plan to test with + win_shell: (Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan | ? {! $_.IsActive}).ElementName[0] + register: disabled_power_plan + changed_when: False + + - set_fact: + name: "{{ disabled_power_plan.stdout_lines[0] }}" + + #Test that plan detects change is needed, but doesn't actually apply change + - name: set power plan (check mode) + win_power_plan: + name: "{{ name }}" + register: set_plan_check + check_mode: yes + +# - debug: +# var: set_plan_check + + - name: get result of set power plan (check mode) + win_shell: (Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan -Filter "ElementName = '{{ name }}'").IsActive + register: set_plan_check_result + changed_when: False + + # verify that the powershell check is showing the plan as still inactive on the system + - name: assert setting plan (check mode) + assert: + that: + - set_plan_check|changed + - set_plan_check_result.stdout == 'False\r\n' + + #Test that setting plan and that change is applied + - name: set power plan + win_power_plan: + name: "{{ name }}" + register: set_plan + + - name: get result of set power plan + win_shell: (Get-CimInstance -Name root\cimv2\power -Class win32_PowerPlan -Filter "ElementName = '{{ name }}'").IsActive + register: set_plan_result + changed_when: False + + - name: assert setting plan + assert: + that: + - set_plan|changed + - set_plan_result.stdout == 'True\r\n' + + #Test that plan doesn't apply change if it is already set + - name: set power plan (idempotent) + win_power_plan: + name: "{{ name }}" + register: set_plan_idempotent + + - name: assert setting plan (idempotent) + assert: + that: + - not set_plan_idempotent|changed + + when: os_version.stdout_lines[0] | version_compare('6.1','ge') + always: + - name: always change back plan to high performance when done testing + win_power_plan: + name: high performance