From 2f70360698341cd3d6b86d5bea8176eb1fa57c72 Mon Sep 17 00:00:00 2001
From: Jordan Borean <jborean93@gmail.com>
Date: Thu, 17 May 2018 11:41:37 +1000
Subject: [PATCH] Add windows module for changing the hostname (#40295)

Co-authored-by: Ripon Banik <riponbanik@users.noreply.github.com>
---
 lib/ansible/modules/windows/win_hostname.ps1  | 30 ++++++++++
 lib/ansible/modules/windows/win_hostname.py   | 48 ++++++++++++++++
 test/integration/targets/win_hostname/aliases |  1 +
 .../targets/win_hostname/defaults/main.yml    |  2 +
 .../targets/win_hostname/tasks/main.yml       | 18 ++++++
 .../targets/win_hostname/tasks/test.yml       | 56 +++++++++++++++++++
 6 files changed, 155 insertions(+)
 create mode 100644 lib/ansible/modules/windows/win_hostname.ps1
 create mode 100644 lib/ansible/modules/windows/win_hostname.py
 create mode 100644 test/integration/targets/win_hostname/aliases
 create mode 100644 test/integration/targets/win_hostname/defaults/main.yml
 create mode 100644 test/integration/targets/win_hostname/tasks/main.yml
 create mode 100644 test/integration/targets/win_hostname/tasks/test.yml

diff --git a/lib/ansible/modules/windows/win_hostname.ps1 b/lib/ansible/modules/windows/win_hostname.ps1
new file mode 100644
index 00000000000..0d9f3e9d850
--- /dev/null
+++ b/lib/ansible/modules/windows/win_hostname.ps1
@@ -0,0 +1,30 @@
+#!powershell
+# Copyright: (c) 2018, Ripon Banik (@riponbanik)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#Requires -Module Ansible.ModuleUtils.Legacy
+
+$ErrorActionPreference = "Stop"
+
+$params = Parse-Args $args -supports_check_mode $true
+$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true
+$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
+
+$current_computer_name = $env:ComputerName
+$result = @{
+   changed = $false
+   old_name = $current_computer_name
+   reboot_required = $false
+}
+
+if ($name -ne $current_computer_name) {
+    Try {
+        Rename-Computer -NewName $name -Force -WhatIf:$check_mode
+    } Catch {
+        Fail-Json -obj $result -message "Failed to rename computer to '$name': $($_.Exception.Message)"
+    }
+    $result.changed = $true
+    $result.reboot_required = $true
+}
+
+Exit-Json -obj $result
diff --git a/lib/ansible/modules/windows/win_hostname.py b/lib/ansible/modules/windows/win_hostname.py
new file mode 100644
index 00000000000..e9ba7c7dafe
--- /dev/null
+++ b/lib/ansible/modules/windows/win_hostname.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# this is a windows documentation stub.  actual code lives in the .ps1
+# file of the same name
+
+# Copyright: (c) 2018, Ripon Banik (@riponbanik)
+# 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 = r'''
+---
+module: win_hostname
+version_added: "2.6"
+short_description: Manages local Windows computer name.
+description:
+- Manages local Windows computer name.
+- A reboot is required for the computer name to take effect.
+options:
+  name:
+    description:
+    - The hostname to set for the computer.
+    required: true
+author:
+- Ripon Banik (@riponbanik)
+'''
+
+EXAMPLES = r'''
+- name: Change the hostname to new_hostname
+  win_hostname:
+    name: new_hostname
+'''
+
+RETURN = r'''
+old_name:
+  description: The original hostname that was set before it was changed
+  returned: always
+  type: str
+  sample: old_hostname
+reboot_required:
+  description: Whether a reboot is required to complete the hostname change
+  returned: always
+  type: bool
+  sample: true
+'''
diff --git a/test/integration/targets/win_hostname/aliases b/test/integration/targets/win_hostname/aliases
new file mode 100644
index 00000000000..c6d61981670
--- /dev/null
+++ b/test/integration/targets/win_hostname/aliases
@@ -0,0 +1 @@
+windows/ci/group3
diff --git a/test/integration/targets/win_hostname/defaults/main.yml b/test/integration/targets/win_hostname/defaults/main.yml
new file mode 100644
index 00000000000..dfc956db299
--- /dev/null
+++ b/test/integration/targets/win_hostname/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+test_win_hostname_name: abcdef-123
diff --git a/test/integration/targets/win_hostname/tasks/main.yml b/test/integration/targets/win_hostname/tasks/main.yml
new file mode 100644
index 00000000000..6f4df9be779
--- /dev/null
+++ b/test/integration/targets/win_hostname/tasks/main.yml
@@ -0,0 +1,18 @@
+---
+- name: get the current hostname
+  win_command: hostname
+  register: current_hostname
+
+- block:
+  - name: run tests
+    include_tasks: test.yml
+
+  always:
+  - name: reset the hostname back to the original
+    win_hostname:
+      name: '{{current_hostname.stdout_lines[0]}}'
+    register: reset_hostname
+
+  - name: reboot if required
+    win_reboot:
+    when: reset_hostname.reboot_required
diff --git a/test/integration/targets/win_hostname/tasks/test.yml b/test/integration/targets/win_hostname/tasks/test.yml
new file mode 100644
index 00000000000..6c3c247a049
--- /dev/null
+++ b/test/integration/targets/win_hostname/tasks/test.yml
@@ -0,0 +1,56 @@
+---
+- name: fail to set hostname to an invalid name
+  win_hostname:
+    name: invalid/name
+  register: fail_hostname
+  failed_when: '"Failed to rename computer to ''invalid/name''" not in fail_hostname.msg'
+
+- name: change the hostname (check)
+  win_hostname:
+    name: '{{test_win_hostname_name}}'
+  register: change_hostname_check
+  check_mode: yes
+
+- name: get actual hostname
+  win_shell: $env:COMPUTERNAME
+  register: change_hostname_actual_check
+
+- name: assert change the hostname (check)
+  assert:
+    that:
+    - change_hostname_check is changed
+    - change_hostname_check.old_name|upper != test_win_hostname_name|upper
+    - change_hostname_check.reboot_required
+    - change_hostname_actual_check.stdout_lines[0]|upper != test_win_hostname_name|upper
+
+- name: change the hostname
+  win_hostname:
+    name: '{{test_win_hostname_name}}'
+  register: change_hostname
+
+- name: reboot after changing the hostname
+  win_reboot:
+
+- name: get actual hostname
+  win_shell: $env:COMPUTERNAME
+  register: change_hostname_actual
+
+- name: assert change the hostname
+  assert:
+    that:
+    - change_hostname is changed
+    - change_hostname.old_name|upper == change_hostname_check.old_name|upper
+    - change_hostname.reboot_required
+    - change_hostname_actual.stdout_lines[0]|upper == test_win_hostname_name|upper
+
+- name: change the hostname (idempotent)
+  win_hostname:
+    name: '{{test_win_hostname_name}}'
+  register: change_hostname_again
+
+- name: assert change the hostname (idempotent)
+  assert:
+    that:
+    - not change_hostname_again is changed
+    - change_hostname_again.old_name|upper == test_win_hostname_name|upper
+    - not change_hostname_again.reboot_required