diff --git a/lib/ansible/modules/windows/win_initialize_disk.ps1 b/lib/ansible/modules/windows/win_initialize_disk.ps1 new file mode 100644 index 00000000000..556c74b3725 --- /dev/null +++ b/lib/ansible/modules/windows/win_initialize_disk.ps1 @@ -0,0 +1,151 @@ +#!powershell + +# Copyright: (c) 2019, Brant Evans +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.Basic +#AnsibleRequires -OSVersion 6.2 + +Set-StrictMode -Version 2 + +$spec = @{ + options = @{ + disk_number = @{ type = "int" } + uniqueid = @{ type = "str" } + path = @{ type = "str" } + style = @{ type = "str"; choices = "gpt", "mbr"; default = "gpt" } + online = @{ type = "bool"; default = $true } + force = @{ type = "bool"; default = $false } + } + mutually_exclusive = @( + ,@('disk_number', 'uniqueid', 'path') + ) + required_one_of = @( + ,@('disk_number', 'uniqueid', 'path') + ) + supports_check_mode = $true +} + +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +$disk_number = $module.Params.disk_number +$uniqueid = $module.Params.uniqueid +$path = $module.Params.path +$partition_style = $module.Params.style +$bring_online = $module.Params.online +$force_init = $module.Params.force + +function Get-AnsibleDisk { + param( + $DiskNumber, + $UniqueId, + $Path + ) + + if ($null -ne $DiskNumber) { + try { + $disk = Get-Disk -Number $DiskNumber + } catch { + $module.FailJson("There was an error retrieving the disk using disk_number $($DiskNumber): $($_.Exception.Message)") + } + } elseif ($null -ne $UniqueId) { + try { + $disk = Get-Disk -UniqueId $UniqueId + } catch { + $module.FailJson("There was an error retrieving the disk using id $($UniqueId): $($_.Exception.Message)") + } + } elseif ($null -ne $Path) { + try { + $disk = Get-Disk -Path $Path + } catch { + $module.FailJson("There was an error retrieving the disk using path $($Path): $($_.Exception.Message)") + } + } else { + $module.FailJson("Unable to retrieve disk: disk_number, id, or path was not specified") + } + + return $disk +} + +function Initialize-AnsibleDisk { + param( + $AnsibleDisk, + $PartitionStyle + ) + + if ($AnsibleDisk.IsReadOnly) { + $module.FailJson("Unable to initialize disk as it is read-only") + } + + $parameters = @{ + Number = $AnsibleDisk.Number + PartitionStyle = $PartitionStyle + } + + if (-Not $module.CheckMode) { + Initialize-Disk @parameters -Confirm:$false + } + + $module.Result.changed = $true +} + +function Clear-AnsibleDisk { + param( + $AnsibleDisk + ) + + $parameters = @{ + Number = $AnsibleDisk.Number + } + + if (-Not $module.CheckMode) { + Clear-Disk @parameters -RemoveData -RemoveOEM -Confirm:$false + } +} + +function Set-AnsibleDisk { + param( + $AnsibleDisk, + $BringOnline + ) + + $refresh_disk_status = $false + + if ($BringOnline) { + if (-Not $module.CheckMode) { + if ($AnsibleDisk.IsOffline) { + Set-Disk -Number $AnsibleDisk.Number -IsOffline:$false + $refresh_disk_status = $true + } + + if ($AnsibleDisk.IsReadOnly) { + Set-Disk -Number $AnsibleDisk.Number -IsReadOnly:$false + $refresh_disk_status = $true + } + } + } + + if ($refresh_disk_status) { + $AnsibleDisk = Get-AnsibleDisk -DiskNumber $AnsibleDisk.Number + } + + return $AnsibleDisk +} + +$ansible_disk = Get-AnsibleDisk -DiskNumber $disk_number -UniqueId $uniqueid -Path $path +$ansible_part_style = $ansible_disk.PartitionStyle + +if ("RAW" -eq $ansible_part_style) { + $ansible_disk = Set-AnsibleDisk -AnsibleDisk $ansible_disk -BringOnline $bring_online + Initialize-AnsibleDisk -AnsibleDisk $ansible_disk -PartitionStyle $partition_style +} else { + if (($ansible_part_style -ne $partition_style.ToUpper()) -And -Not $force_init) { + $module.FailJson("Force initialization must be specified since the target partition style: $($partition_style.ToLower()) is different from the current partition style: $($ansible_part_style.ToLower())") + } elseif ($force_init) { + $ansible_disk = Set-AnsibleDisk -AnsibleDisk $ansible_disk -BringOnline $bring_online + Clear-AnsibleDisk -AnsibleDisk $ansible_disk + Initialize-AnsibleDisk -AnsibleDisk $ansible_disk -PartitionStyle $partition_style + } +} + +$module.ExitJson() diff --git a/lib/ansible/modules/windows/win_initialize_disk.py b/lib/ansible/modules/windows/win_initialize_disk.py new file mode 100644 index 00000000000..8328bb0294a --- /dev/null +++ b/lib/ansible/modules/windows/win_initialize_disk.py @@ -0,0 +1,88 @@ +#!/usr/bin/python + +# Copyright: (c) 2019, Brant Evans +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +DOCUMENTATION = ''' +--- +module: win_initialize_disk + +short_description: Initializes disks on Windows Server + +version_added: "2.10" + +description: + - "The M(win_initialize_disk) module initializes disks" + +options: + disk_number: + description: + - Used to specify the disk number of the disk to be initialized. + type: int + uniqueid: + description: + - Used to specify the uniqueid of the disk to be initialized. + type: str + path: + description: + - Used to specify the path to the disk to be initialized. + type: str + style: + description: + - The partition style to use for the disk. Valid options are mbr or gpt. + type: str + choices: [ gpt, mbr ] + default: gpt + online: + description: + - If the disk is offline and/or readonly update the disk to be online and not readonly. + type: bool + default: true + force: + description: + - Specify if initializing should be forced for disks that are already initialized. + type: bool + +notes: + - One of three parameters (I(disk_number), I(uniqueid), and I(path)) are mandatory to identify the target disk, but + more than one cannot be specified at the same time. + - A minimum Operating System Version of Server 2012 or Windows 8 is required to use this module. + - This module is idempotent if I(force) is not specified. + +seealso: + - module: win_disk_facts + - module: win_partition + - module: win_format + +author: + - Brant Evans (@branic) +''' + +EXAMPLES = ''' +- name: Initialize a disk + win_initialize_disk: + disk_number: 1 + +- name: Initialize a disk with an MBR partition style + win_initialize_disk: + disk_number: 1 + style: mbr + +- name: Forcefully initiallize a disk + win_initialize_disk: + disk_number: 2 + force: yes +''' + +RETURN = ''' +# +''' diff --git a/test/integration/targets/win_initialize_disk/aliases b/test/integration/targets/win_initialize_disk/aliases new file mode 100644 index 00000000000..3fac36743f2 --- /dev/null +++ b/test/integration/targets/win_initialize_disk/aliases @@ -0,0 +1,3 @@ +shippable/windows/group6 +skip/windows/2008 +skip/windows/2008-R2 diff --git a/test/integration/targets/win_initialize_disk/defaults/main.yml b/test/integration/targets/win_initialize_disk/defaults/main.yml new file mode 100644 index 00000000000..9cb54a30cd7 --- /dev/null +++ b/test/integration/targets/win_initialize_disk/defaults/main.yml @@ -0,0 +1 @@ +AnsibleVhdx: C:\win_initialize_disk_tests\AnsiblePart.vhdx diff --git a/test/integration/targets/win_initialize_disk/tasks/main.yml b/test/integration/targets/win_initialize_disk/tasks/main.yml new file mode 100644 index 00000000000..f31c751392d --- /dev/null +++ b/test/integration/targets/win_initialize_disk/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: Create the temp directory + win_file: + path: C:\win_initialize_disk_tests + state: directory + +- name: Copy VHDX scripts + win_template: + src: "{{ item.src }}" + dest: C:\win_initialize_disk_tests\{{ item.dest }} + loop: + - { src: vhdx_creation_script.j2, dest: vhdx_creation_script.txt } + - { src: vhdx_deletion_script.j2, dest: vhdx_deletion_script.txt } + +- name: Create VHD + win_command: diskpart.exe /s C:\win_initialize_disk_tests\vhdx_creation_script.txt + +- name: Run tests + block: + - include: tests.yml + always: + - name: Detach disk + win_command: diskpart.exe /s C:\win_initialize_disk_tests\vhdx_deletion_script.txt + + - name: Cleanup files + win_file: + path: C:\win_initialize_disk_tests + state: absent diff --git a/test/integration/targets/win_initialize_disk/tasks/tests.yml b/test/integration/targets/win_initialize_disk/tasks/tests.yml new file mode 100644 index 00000000000..41defd60621 --- /dev/null +++ b/test/integration/targets/win_initialize_disk/tasks/tests.yml @@ -0,0 +1,104 @@ +--- +- name: Initialize the disk with the default partition style (check mode) + win_initialize_disk: + disk_number: 1 + register: default_part_style_check + check_mode: yes + +- name: Get result of default initialization (check mode) + win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'RAW' ) {'true'} else {'false'}" + register: default_part_style_actual_check + +- name: assert default initialization (check mode) + assert: + that: + - default_part_style_check is changed + - default_part_style_actual_check.stdout == 'true\r\n' + +- name: Initialize the disk with the default partition style + win_initialize_disk: + disk_number: 1 + register: default_part_style + +- name: Get result of default initialization + win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'GPT' ) {'true'} else {'false'}" + register: default_part_style_actual + +- name: assert default initialization + assert: + that: + - default_part_style is changed + - default_part_style_actual.stdout == 'true\r\n' + +- name: Initialize the disk with the default partition style (idempotence) + win_initialize_disk: + disk_number: 1 + register: default_part_style_idempotence + +- name: Get result of default initialization (idempotence) + win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'GPT' ) {'true'} else {'false'}" + register: default_part_style_actual_idempotence + +- name: assert default initialization (idempotence) + assert: + that: + - not default_part_style_idempotence is changed + - default_part_style_actual_idempotence.stdout == 'true\r\n' + +- name: Partition style change without force fails + win_initialize_disk: + disk_number: 1 + style: mbr + register: change_part_style + ignore_errors: True + +- name: assert failed partition style change + assert: + that: + - change_part_style is failed + +- name: Partition style change with force is successful (check mode) + win_initialize_disk: + disk_number: 1 + style: mbr + force: yes + register: change_part_style_forced_check + check_mode: yes + +- name: Get result of forced initialization (check mode) + win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'GPT' ) {'true'} else {'false'}" + register: change_part_style_forced_actual_check + +- name: assert forced initialization (check mode) + assert: + that: + - change_part_style_forced_check is changed + - change_part_style_forced_actual_check.stdout == 'true\r\n' + +- name: Partition style change with force is successful + win_initialize_disk: + disk_number: 1 + style: mbr + force: yes + register: change_part_style_forced + +- name: Get result of forced initialization + win_command: powershell.exe "if ( (Get-Disk -Number 1).PartitionStyle -eq 'MBR' ) {'true'} else {'false'}" + register: change_part_style_forced_actual + +- name: assert forced initialization + assert: + that: + - change_part_style_forced is changed + - change_part_style_forced_actual.stdout == 'true\r\n' + +- name: Unknown disk number fails + win_initialize_disk: + disk_number: 3 + register: unknown_disk_number + ignore_errors: True + +- name: assert unknown disk number fails + assert: + that: + - unknown_disk_number is failed diff --git a/test/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j2 b/test/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j2 new file mode 100644 index 00000000000..4089bf379e9 --- /dev/null +++ b/test/integration/targets/win_initialize_disk/templates/vhdx_creation_script.j2 @@ -0,0 +1,5 @@ +create vdisk file="{{ AnsibleVhdx }}" maximum=2000 type=fixed + +select vdisk file="{{ AnsibleVhdx }}" + +attach vdisk diff --git a/test/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j2 b/test/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j2 new file mode 100644 index 00000000000..c2be9cd1446 --- /dev/null +++ b/test/integration/targets/win_initialize_disk/templates/vhdx_deletion_script.j2 @@ -0,0 +1,3 @@ +select vdisk file="{{ AnsibleVhdx }}" + +detach vdisk