diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-26 06:22:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-26 06:22:20 +0000 |
commit | 18bd2207b6c1977e99a93673a7be099e23f0f547 (patch) | |
tree | 40fd9e5913462a88be6ba24be6953383c5b39874 /ansible_collections/microsoft/ad/tests/integration | |
parent | Releasing progress-linux version 10.0.1+dfsg-1~progress7.99u1. (diff) | |
download | ansible-18bd2207b6c1977e99a93673a7be099e23f0f547.tar.xz ansible-18bd2207b6c1977e99a93673a7be099e23f0f547.zip |
Merging upstream version 10.1.0+dfsg.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/microsoft/ad/tests/integration')
15 files changed, 1400 insertions, 49 deletions
diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/computer/tasks/tests.yml b/ansible_collections/microsoft/ad/tests/integration/targets/computer/tasks/tests.yml index 2a403c3d5..3619df40b 100644 --- a/ansible_collections/microsoft/ad/tests/integration/targets/computer/tasks/tests.yml +++ b/ansible_collections/microsoft/ad/tests/integration/targets/computer/tasks/tests.yml @@ -99,14 +99,41 @@ that: - not remove_comp_again is changed +- name: expect failure with invalid DN lookup entry - no name + computer: + name: MyComputer + state: present + delegates: + set: + - CN=krbtgt,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + - server: fail + register: invalid_dn_lookup_no_name + failed_when: >- + invalid_dn_lookup_no_name.msg != "Failed to find the AD object DNs for delegates.set. Identity entry does not contain the required name key." + +- name: expect failure with invalid DN lookup entry - extra keys + computer: + name: MyComputer + state: present + delegates: + add: + - name: name + invalid2: bar + invalid1: foo + register: invalid_dn_lookup_extra_keys + failed_when: >- + invalid_dn_lookup_extra_keys.msg != "Failed to find the AD object DNs for delegates.add. Identity entry for 'name' contains extra keys: 'invalid1', 'invalid2'." + - name: create computer with custom options computer: name: MyComputer state: present delegates: + lookup_failure_action: ignore set: - CN=krbtgt,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} - - CN=Administrator,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + - name: CN=Administrator,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + - CN=Missing,{{ setup_domain_info.output[0].defaultNamingContext }} kerberos_encryption_types: set: - aes128 @@ -188,8 +215,11 @@ name: MyComputer path: CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} delegates: + lookup_failure_action: warn set: - - CN=KRBTGT,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + - name: CN=KRBTGT,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + - '' + - CN=Missing,{{ setup_domain_info.output[0].defaultNamingContext }} dns_hostname: other.domain.com kerberos_encryption_types: set: @@ -236,6 +266,9 @@ assert: that: - change_comp is changed + - change_comp.warnings | length == 1 + - >- + change_comp.warnings[0] == "Failed to find the AD object DNs for delegates.set. Ignoring invalid identities: 'CN=Missing," ~ setup_domain_info.output[0].defaultNamingContext ~ "'" - change_comp_actual.objects[0].dnsHostName == 'other.domain.com' - change_comp_actual.objects[0].location == 'comp location' - change_comp_actual.objects[0]['msDS-SupportedEncryptionTypes'] == 20 @@ -247,6 +280,17 @@ - '"ADS_UF_TRUSTED_FOR_DELEGATION" not in change_comp_actual.objects[0].userAccountControl_AnsibleFlags' - change_comp_delegates.output == ["krbtgt"] +- name: fail with invalid delegate identity + computer: + name: MyComputer + path: CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + delegates: + set: + - CN=Missing,{{ setup_domain_info.output[0].defaultNamingContext }} + register: invalid_delegate + failed_when: >- + invalid_delegate.msg != "Failed to find the AD object DNs for delegates.set. Invalid identities: 'CN=Missing," ~ setup_domain_info.output[0].defaultNamingContext ~ "'" + - name: add and remove list options computer: name: MyComputer @@ -254,9 +298,10 @@ delegates: add: - CN=Administrator,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} + - '' remove: + - name: '' - CN=KRBTGT,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} - - CN=Missing,{{ setup_domain_info.output[0].defaultNamingContext }} kerberos_encryption_types: add: - aes128 @@ -305,7 +350,6 @@ - CN=Administrator,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} remove: - CN=KRBTGT,CN=Users,{{ setup_domain_info.output[0].defaultNamingContext }} - - CN=Missing,{{ setup_domain_info.output[0].defaultNamingContext }} kerberos_encryption_types: add: - aes128 diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/README.md b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/README.md new file mode 100644 index 000000000..f7bc08ff1 --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/README.md @@ -0,0 +1,36 @@ +# microsoft.ad.domain_child tests + +As this cannot be run in CI this is a brief guide on how to run these tests locally. +Run the following: + +```bash +vagrant up + +ansible-playbook setup.yml +``` + +It is a good idea to create a snapshot of both hosts before running the tests. +This allows you to reset the host back to a blank starting state if the tests need to be rerun. +To create a snapshot do the following: + +```bash +virsh snapshot-create-as --domain "domain_child_PARENT" --name "pretest" +virsh snapshot-create-as --domain "domain_child_CHILD" --name "pretest" +virsh snapshot-create-as --domain "domain_child_TREE" --name "pretest" +``` + +To restore these snapshots run the following: + +```bash +virsh snapshot-revert --domain "domain_child_PARENT" --snapshotname "pretest" --running +virsh snapshot-revert --domain "domain_child_CHILD" --snapshotname "pretest" --running +virsh snapshot-revert --domain "domain_child_TREE" --snapshotname "pretest" --running +``` + +Once you are ready to run the tests run the following: + +```bash +ansible-playbook test.yml +``` + +Run `vagrant destroy` to remove the test VMs. diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/Vagrantfile b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/Vagrantfile new file mode 100644 index 000000000..13af40311 --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/Vagrantfile @@ -0,0 +1,27 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +require 'yaml' + +inventory = YAML.load_file('inventory.yml') + +Vagrant.configure("2") do |config| + inventory['all']['children'].each do |group,details| + details['hosts'].each do |server,host_details| + config.vm.define server do |srv| + srv.vm.box = host_details['vagrant_box'] + srv.vm.hostname = server + srv.vm.network :private_network, + :ip => host_details['ansible_host'], + :libvirt__network_name => 'microsoft.ad', + :libvirt__domain_name => inventory['all']['vars']['domain_realm'] + + srv.vm.provider :libvirt do |l| + l.memory = 8192 + l.cpus = 4 + end + end + end + end +end + diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/aliases b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/aliases new file mode 100644 index 000000000..435ff207d --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/aliases @@ -0,0 +1,2 @@ +windows +unsupported # can never run in CI, see README.md diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/ansible.cfg b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/ansible.cfg new file mode 100644 index 000000000..cfedec78f --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +callback_result_format = yaml +inventory = inventory.yml +retry_files_enabled = False diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/inventory.yml b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/inventory.yml new file mode 100644 index 000000000..e57f75516 --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/inventory.yml @@ -0,0 +1,28 @@ +all: + children: + windows: + hosts: + PARENT: + ansible_host: 192.168.11.10 + vagrant_box: jborean93/WindowsServer2022 + CHILD: + ansible_host: 192.168.11.11 + vagrant_box: jborean93/WindowsServer2022 + new_hostname: foo + child_domain_name: child.ad.test + TREE: + ansible_host: 192.168.11.12 + vagrant_box: jborean93/WindowsServer2022 + new_hostname: bar + child_domain_name: tree.test + vars: + ansible_port: 5985 + ansible_connection: psrp + + vars: + ansible_user: vagrant + ansible_password: vagrant + domain_username: vagrant-domain + domain_user_upn: '{{ domain_username }}@{{ domain_realm | upper }}' + domain_password: VagrantPass1 + domain_realm: ad.test diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/setup.yml b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/setup.yml new file mode 100644 index 000000000..de0843829 --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/setup.yml @@ -0,0 +1,71 @@ +- name: setup common Windows information + hosts: windows + gather_facts: no + + tasks: + - name: get network connection names + ansible.windows.win_powershell: + parameters: + IPAddress: '{{ ansible_host }}' + script: | + param ($IPAddress) + + $Ansible.Changed = $false + + Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "Netenabled='True'" | + ForEach-Object -Process { + $config = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index='$($_.Index)'" + if ($config.IPAddress -contains $IPAddress) { + $_.NetConnectionID + } + } + register: connection_name + +- name: create parent forest + hosts: PARENT + gather_facts: no + + tasks: + - name: set the DNS for the internal adapters to localhost + ansible.windows.win_dns_client: + adapter_names: + - '{{ connection_name.output[0] }}' + dns_servers: + - 127.0.0.1 + + - name: ensure domain exists and DC is promoted as a domain controller + microsoft.ad.domain: + dns_domain_name: '{{ domain_realm }}' + safe_mode_password: '{{ domain_password }}' + reboot: true + + - name: create parent domain username + microsoft.ad.user: + name: '{{ domain_username }}' + upn: '{{ domain_user_upn }}' + description: '{{ domain_username }} Domain Account' + password: '{{ domain_password }}' + password_never_expires: yes + update_password: when_changed + groups: + add: + - Domain Admins + - Enterprise Admins + state: present + +- name: setup test host + hosts: CHILD,TREE + gather_facts: no + + tasks: + - name: set DNS for the private adapter to point to the parent forest DC + ansible.windows.win_dns_client: + adapter_names: + - '{{ connection_name.output[0] }}' + dns_servers: + - '{{ hostvars["PARENT"]["ansible_host"] }}' + + - name: install RSAT tools for debugging purposes + ansible.windows.win_feature: + name: RSAT-AD-PowerShell + state: present diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/cross_domain.yml b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/cross_domain.yml new file mode 100644 index 000000000..611beedac --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/cross_domain.yml @@ -0,0 +1,596 @@ +- name: create test object in parent domain with domain_username creds - check mode + microsoft.ad.user: + name: ParentUser1 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_username: '{{ domain_user_upn }}' + domain_password: '{{ domain_password }}' + register: user_with_creds1_check + check_mode: true + delegate_to: CHILD + +- name: get result of create test object in parent domain with domain_username creds - check mode + microsoft.ad.object_info: + identity: CN=ParentUser1,{{ parent_ou }} + register: user_with_creds1_check_actual + delegate_to: PARENT + +- name: assert create test object in parent domain with domain_username creds - check mode + assert: + that: + - user_with_creds1_check is changed + - user_with_creds1_check.distinguished_name == "CN=ParentUser1," ~ parent_ou + - user_with_creds1_check_actual.objects == [] + +- name: create test object in parent domain with domain_username creds + microsoft.ad.user: + name: ParentUser1 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_username: '{{ domain_user_upn }}' + domain_password: '{{ domain_password }}' + register: user_with_creds1 + delegate_to: CHILD + +- name: get result of create test object in parent domain with domain_username creds + microsoft.ad.object_info: + identity: CN=ParentUser1,{{ parent_ou }} + register: user_with_creds1_actual + delegate_to: PARENT + +- name: assert create test object in parent domain with domain_username creds + assert: + that: + - user_with_creds1 is changed + - user_with_creds1.distinguished_name == "CN=ParentUser1," ~ parent_ou + - user_with_creds1_actual.objects | count == 1 + - user_with_creds1_actual.objects[0].ObjectGUID == user_with_creds1.object_guid + - user_with_creds1_actual.objects[0].DistinguishedName == user_with_creds1.distinguished_name + +- name: create test object in parent domain with domain_username creds - idempotent + microsoft.ad.user: + name: ParentUser1 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_username: '{{ domain_user_upn }}' + domain_password: '{{ domain_password }}' + register: user_with_creds1_again + delegate_to: CHILD + +- name: assert create test object in parent domain with domain_username creds - idempotent + assert: + that: + - not user_with_creds1_again is changed + - user_with_creds1_again.distinguished_name == user_with_creds1.distinguished_name + - user_with_creds1_again.object_guid == user_with_creds1.object_guid + +- name: create test object in parent domain with domain_credentials creds - check mode + microsoft.ad.user: + name: ParentUser2 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_credentials: + - username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + register: user_with_creds2_check + check_mode: true + delegate_to: CHILD + +- name: get result of create test object in parent domain with domain_credentials creds - check mode + microsoft.ad.object_info: + identity: CN=ParentUser2,{{ parent_ou }} + register: user_with_creds2_check_actual + delegate_to: PARENT + +- name: assert create test object in parent domain with domain_credentials creds - check mode + assert: + that: + - user_with_creds2_check is changed + - user_with_creds2_check.distinguished_name == "CN=ParentUser2," ~ parent_ou + - user_with_creds2_check_actual.objects == [] + +- name: create test object in parent domain with domain_credentials creds + microsoft.ad.user: + name: ParentUser2 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_credentials: + - username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + register: user_with_creds2 + delegate_to: CHILD + +- name: get result of create test object in parent domain with domain_credentials creds + microsoft.ad.object_info: + identity: CN=ParentUser2,{{ parent_ou }} + register: user_with_creds2_actual + delegate_to: PARENT + +- name: assert create test object in parent domain with domain_credentials creds + assert: + that: + - user_with_creds2 is changed + - user_with_creds2.distinguished_name == "CN=ParentUser2," ~ parent_ou + - user_with_creds2_actual.objects | count == 1 + - user_with_creds2_actual.objects[0].ObjectGUID == user_with_creds2.object_guid + - user_with_creds2_actual.objects[0].DistinguishedName == user_with_creds2.distinguished_name + +- name: create test object in parent domain with domain_credentials creds - idempotent + microsoft.ad.user: + name: ParentUser2 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_credentials: + - username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + register: user_with_creds2_again + delegate_to: CHILD + +- name: assert create test object in parent domain with domain_credentials creds - idempotent + assert: + that: + - not user_with_creds2_again is changed + - user_with_creds2_again.distinguished_name == user_with_creds2.distinguished_name + - user_with_creds2_again.object_guid == user_with_creds2.object_guid + +- name: edit user with domain_username creds - check mode + microsoft.ad.user: + name: ParentUser1 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_username: '{{ domain_user_upn }}' + domain_password: '{{ domain_password }}' + description: User Description + spn: + set: + - HTTP/ParentUser1 + attributes: + set: + comment: My comment + register: set_with_creds1_check + delegate_to: CHILD + check_mode: true + +- name: get result of set user with domain_username creds - check mode + microsoft.ad.object_info: + identity: '{{ user_with_creds1.object_guid }}' + properties: + - comment + - Description + - servicePrincipalName + register: set_with_creds1_check_actual + delegate_to: PARENT + +- name: assert set user with domain_username creds - check mode + assert: + that: + - set_with_creds1_check is changed + - set_with_creds1_check.distinguished_name == user_with_creds1.distinguished_name + - set_with_creds1_check.object_guid == user_with_creds1.object_guid + - set_with_creds1_check_actual.objects[0].Description == None + - set_with_creds1_check_actual.objects[0].DistinguishedName == user_with_creds1.distinguished_name + - set_with_creds1_check_actual.objects[0].Name == 'ParentUser1' + - set_with_creds1_check_actual.objects[0].ObjectGUID == user_with_creds1.object_guid + - set_with_creds1_check_actual.objects[0].comment == None + - set_with_creds1_check_actual.objects[0].servicePrincipalName == None + +- name: edit user with domain_username creds + microsoft.ad.user: + name: ParentUser1 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_username: '{{ domain_user_upn }}' + domain_password: '{{ domain_password }}' + description: User Description + spn: + set: + - HTTP/ParentUser1 + attributes: + set: + comment: My comment + register: set_with_creds1 + delegate_to: CHILD + +- name: get result of set user with domain_username creds + microsoft.ad.object_info: + identity: '{{ user_with_creds1.object_guid }}' + properties: + - comment + - Description + - servicePrincipalName + register: set_with_creds1_actual + delegate_to: PARENT + +- name: assert set user with domain_username creds + assert: + that: + - set_with_creds1 is changed + - set_with_creds1.distinguished_name == user_with_creds1.distinguished_name + - set_with_creds1.object_guid == user_with_creds1.object_guid + - set_with_creds1_actual.objects[0].Description == "User Description" + - set_with_creds1_actual.objects[0].DistinguishedName == user_with_creds1.distinguished_name + - set_with_creds1_actual.objects[0].Name == 'ParentUser1' + - set_with_creds1_actual.objects[0].ObjectGUID == user_with_creds1.object_guid + - set_with_creds1_actual.objects[0].comment == "My comment" + - set_with_creds1_actual.objects[0].servicePrincipalName == "HTTP/ParentUser1" + +- name: edit user with domain_credentials creds - check mode + microsoft.ad.user: + name: ParentUser2 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_credentials: + - username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + description: User Description + spn: + set: + - HTTP/ParentUser2 + attributes: + set: + comment: My comment + register: set_with_creds2_check + delegate_to: CHILD + check_mode: true + +- name: get result of set user with domain_credentials creds - check mode + microsoft.ad.object_info: + identity: '{{ user_with_creds2.object_guid }}' + properties: + - comment + - Description + - servicePrincipalName + register: set_with_creds2_check_actual + delegate_to: PARENT + +- name: assert set user with domain_credentials creds - check mode + assert: + that: + - set_with_creds2_check is changed + - set_with_creds2_check.distinguished_name == user_with_creds2.distinguished_name + - set_with_creds2_check.object_guid == user_with_creds2.object_guid + - set_with_creds2_check_actual.objects[0].Description == None + - set_with_creds2_check_actual.objects[0].DistinguishedName == user_with_creds2.distinguished_name + - set_with_creds2_check_actual.objects[0].Name == 'ParentUser2' + - set_with_creds2_check_actual.objects[0].ObjectGUID == user_with_creds2.object_guid + - set_with_creds2_check_actual.objects[0].comment == None + - set_with_creds2_check_actual.objects[0].servicePrincipalName == None + +- name: edit user with domain_credentials creds + microsoft.ad.user: + name: ParentUser2 + path: '{{ parent_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_server: '{{ domain_realm }}' + domain_credentials: + - username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + description: User Description + spn: + set: + - HTTP/ParentUser2 + attributes: + set: + comment: My comment + register: set_with_creds2 + delegate_to: CHILD + +- name: get result of set user with domain_credentials creds + microsoft.ad.object_info: + identity: '{{ user_with_creds2.object_guid }}' + properties: + - comment + - Description + - servicePrincipalName + register: set_with_creds2_actual + delegate_to: PARENT + +- name: assert set user with domain_credentials creds + assert: + that: + - set_with_creds2 is changed + - set_with_creds2.distinguished_name == user_with_creds2.distinguished_name + - set_with_creds2.object_guid == user_with_creds2.object_guid + - set_with_creds2_actual.objects[0].Description == "User Description" + - set_with_creds2_actual.objects[0].DistinguishedName == user_with_creds2.distinguished_name + - set_with_creds2_actual.objects[0].Name == 'ParentUser2' + - set_with_creds2_actual.objects[0].ObjectGUID == user_with_creds2.object_guid + - set_with_creds2_actual.objects[0].comment == "My comment" + - set_with_creds2_actual.objects[0].servicePrincipalName == "HTTP/ParentUser2" + +- name: set value with DN lookup and creds + microsoft.ad.group: + name: Group-CHILD + path: '{{ child_ou }}' + state: present + members: + add: + - User-CHILD + - name: User-PARENT + server: '{{ domain_realm }}' + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + register: lookup_with_creds + delegate_to: CHILD + +- name: get result of set value with DN lookup and creds + microsoft.ad.object_info: + identity: '{{ lookup_with_creds.object_guid }}' + properties: + - member + register: lookup_with_creds_actual + delegate_to: CHILD + +- name: assert set value with DN lookup and creds + assert: + that: + - lookup_with_creds is changed + - parent_user in lookup_with_creds_actual.objects[0].member + - child_user in lookup_with_creds_actual.objects[0].member + +- name: set value with DN lookup and creds - idempotent + microsoft.ad.group: + name: Group-CHILD + path: '{{ child_ou }}' + state: present + members: + add: + - User-CHILD + - name: User-PARENT + server: '{{ domain_realm }}' + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + register: lookup_with_creds_again + delegate_to: CHILD + +- name: assert set value with DN lookup and creds - idempotent + assert: + that: + - not lookup_with_creds_again is changed + +- name: create user group with DN lookup and creds - check mode + microsoft.ad.user: + name: ChildUser1 + path: '{{ child_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + groups: + add: + - Group-CHILD + - name: Group-PARENT + server: '{{ domain_realm }}' + register: new_user_with_group_check + delegate_to: CHILD + check_mode: true + +- name: get result of create user group with DN lookup and creds - check mode + microsoft.ad.object_info: + identity: '{{ new_user_with_group_check.distinguished_name }}' + properties: + - memberOf + register: new_user_with_group_check_actual + delegate_to: CHILD + +- name: assert set value with DN lookup and creds + assert: + that: + - new_user_with_group_check is changed + - new_user_with_group_check.distinguished_name == "CN=ChildUser1," ~ child_ou + - new_user_with_group_check_actual.objects == [] + +- name: create user group with DN lookup and creds + microsoft.ad.user: + name: ChildUser1 + path: '{{ child_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + groups: + add: + - Group-CHILD + - name: Group-PARENT + server: '{{ domain_realm }}' + register: new_user_with_group + delegate_to: CHILD + +- name: replicate group membership of parent group to child domain after adding group + ansible.windows.win_command: >- + repadmin.exe + /replsingleobj + {{ hostvars["CHILD"]["new_hostname"] }}.{{ hostvars["CHILD"]["child_domain_name"] }} + parent.{{ domain_realm }} + {{ parent_group }} + delegate_to: CHILD + +- name: get result of create user group with DN lookup and creds + microsoft.ad.object_info: + identity: '{{ new_user_with_group.distinguished_name }}' + properties: + - memberOf + register: new_user_with_group_actual + delegate_to: CHILD + +- name: assert create user group with DN lookup and creds + assert: + that: + - new_user_with_group is changed + - new_user_with_group.distinguished_name == "CN=ChildUser1," ~ child_ou + - new_user_with_group_actual.objects | count == 1 + - new_user_with_group_actual.objects[0].DistinguishedName == new_user_with_group.distinguished_name + - >- + "CN=Group-CHILD," ~ child_ou in new_user_with_group_actual.objects[0].memberOf + - >- + "CN=Group-PARENT," ~ parent_ou in new_user_with_group_actual.objects[0].memberOf + +- name: create user group with DN lookup and creds - idempotent + microsoft.ad.user: + name: ChildUser1 + path: '{{ child_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + groups: + add: + - Group-CHILD + - name: Group-PARENT + server: '{{ domain_realm }}' + register: new_user_with_group_again + delegate_to: CHILD + +- name: assert create user group with DN lookup and creds - idempotent + assert: + that: + - not new_user_with_group_again is changed + +- name: remove user group with DN lookup and creds - check mode + microsoft.ad.user: + name: ChildUser1 + path: '{{ child_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + groups: + remove: + - Group-CHILD + - name: Group-PARENT + server: '{{ domain_realm }}' + register: remove_user_with_group_check + delegate_to: CHILD + check_mode: true + +- name: get result of remove user group with DN lookup and creds - check mode + microsoft.ad.object_info: + identity: '{{ remove_user_with_group_check.distinguished_name }}' + properties: + - memberOf + register: remove_user_with_group_check_actual + delegate_to: CHILD + +- name: assert remove user group with DN lookup and creds - check mode + assert: + that: + - remove_user_with_group_check is changed + - remove_user_with_group_check.distinguished_name == "CN=ChildUser1," ~ child_ou + - >- + "CN=Group-CHILD," ~ child_ou in remove_user_with_group_check_actual.objects[0].memberOf + - >- + "CN=Group-PARENT," ~ parent_ou in remove_user_with_group_check_actual.objects[0].memberOf + +- name: remove user group with DN lookup and creds + microsoft.ad.user: + name: ChildUser1 + path: '{{ child_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + groups: + remove: + - Group-CHILD + - name: Group-PARENT + server: '{{ domain_realm }}' + register: remove_user_with_group + delegate_to: CHILD + +- name: replicate group membership of parent group to child domain after removing group + ansible.windows.win_command: >- + repadmin.exe + /replsingleobj + {{ hostvars["CHILD"]["new_hostname"] }}.{{ hostvars["CHILD"]["child_domain_name"] }} + parent.{{ domain_realm }} + {{ parent_group }} + delegate_to: CHILD + +- name: get result of remove user group with DN lookup and creds + microsoft.ad.object_info: + identity: '{{ remove_user_with_group.distinguished_name }}' + properties: + - memberOf + register: remove_user_with_group_actual + delegate_to: CHILD + +- name: assert remove user group with DN lookup and creds + assert: + that: + - remove_user_with_group is changed + - remove_user_with_group.distinguished_name == "CN=ChildUser1," ~ child_ou + - remove_user_with_group_actual.objects | count == 1 + - remove_user_with_group_actual.objects[0].DistinguishedName == new_user_with_group.distinguished_name + - remove_user_with_group_actual.objects[0].memberOf == None + +- name: remove user group with DN lookup and creds - idempotent + microsoft.ad.user: + name: ChildUser1 + path: '{{ child_ou }}' + state: present + password: '{{ domain_password }}' + update_password: when_changed + domain_credentials: + - name: '{{ domain_realm }}' + username: '{{ domain_user_upn }}' + password: '{{ domain_password }}' + groups: + remove: + - Group-CHILD + - name: Group-PARENT + server: '{{ domain_realm }}' + register: remove_user_with_group_again + delegate_to: CHILD + +- name: assert remove user group with DN lookup and creds - idempotent + assert: + that: + - not remove_user_with_group_again is changed diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/main_child.yml b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/main_child.yml new file mode 100644 index 000000000..40f4f2eda --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/main_child.yml @@ -0,0 +1,98 @@ +- name: create child domain - check mode + domain_child: + dns_domain_name: '{{ child_domain_name }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + reboot: true + register: to_domain_check + check_mode: true + +- name: get result of promote to domain - check mode + ansible.windows.win_powershell: + script: '{{ get_role_script }}' + register: to_domain_check_actual + +- name: assert promote to domain - check mode + assert: + that: + - to_domain_check is changed + - to_domain_check_actual.output[0]["Domain"] == None + - to_domain_check_actual.output[0]["DomainRole"] == "StandaloneServer" + +- name: change hostname to have a pending change before promotion + ansible.windows.win_hostname: + name: '{{ new_hostname }}' + +- name: create child domain with pending reboot + domain_child: + dns_domain_name: '{{ child_domain_name }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + reboot: true + register: to_domain + +- name: get result of promote to domain with pending reboot + ansible.windows.win_powershell: + script: '{{ get_role_script }}' + register: to_domain_actual + +- name: assert promote to domain with pending reboot + assert: + that: + - to_domain is changed + - to_domain_actual.output[0]["Domain"] == child_domain_name + - to_domain_actual.output[0]["DomainRole"] == "PrimaryDC" + - to_domain_actual.output[0]["HostName"] == new_hostname | upper + +- name: create child domain - idempotent + domain_child: + dns_domain_name: '{{ child_domain_name }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + reboot: true + register: to_domain_again + +- name: assert create child domain - idempotent + assert: + that: + - not to_domain_again is changed + +- name: fail to change domain of host + domain_child: + dns_domain_name: bogus.local + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + reboot: true + register: change_domain_fail + failed_when: + - change_domain_fail.msg != "Host is already a domain controller in another domain " ~ child_domain_name + +- name: fail with parent_domain_name with domain_type mode + domain_child: + dns_domain_name: '{{ child_domain_name }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + parent_domain_name: other + reboot: true + register: invalid_parent + failed_when: + - invalid_parent.msg != "parent_domain_name must not be set when domain_type=child" + +- name: fail with invalid domain_mode + domain_child: + dns_domain_name: bogus.local + parent_domain_name: '{{ domain_realm }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + domain_mode: Invalid + reboot: true + register: change_domain_invalid_mode + failed_when: + - >- + change_domain_invalid_mode.msg.startswith("The parameter 'domain_mode' does not accept 'Invalid', please use one of: ") diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/main_tree.yml b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/main_tree.yml new file mode 100644 index 000000000..01e5e06b5 --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/tasks/main_tree.yml @@ -0,0 +1,91 @@ +- name: create test folders + ansible.windows.win_file: + path: 'C:\ansible_testing\{{ item }}' + state: directory + loop: + - DB + - LogPath + - SysVol + +- name: create tree domain - check mode + domain_child: + dns_domain_name: '{{ child_domain_name }}' + parent_domain_name: '{{ domain_realm }}' + domain_type: tree + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + domain_mode: WinThreshold + database_path: C:\ansible_testing\DB + log_path: C:\ansible_testing\LogPath + sysvol_path: C:\ansible_testing\SysVol + reboot: true + register: to_tree_check + check_mode: true + +- name: get result of promote to tree domain - check mode + ansible.windows.win_powershell: + script: '{{ get_role_script }}' + register: to_tree_check_actual + +- name: assert promote to domain - check mode + assert: + that: + - to_tree_check is changed + - not to_tree_check.reboot_required + - to_tree_check_actual.output[0]["Domain"] == None + - to_tree_check_actual.output[0]["DomainRole"] == "StandaloneServer" + +- name: change hostname to have a pending change before promotion + ansible.windows.win_hostname: + name: '{{ new_hostname }}' + +- name: create tree domain with pending reboot + domain_child: + dns_domain_name: '{{ child_domain_name }}' + parent_domain_name: '{{ domain_realm }}' + domain_type: tree + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + domain_mode: WinThreshold + database_path: C:\ansible_testing\DB + log_path: C:\ansible_testing\LogPath + sysvol_path: C:\ansible_testing\SysVol + reboot: true + register: to_tree + +- name: get result of promote to domain with pending reboot + ansible.windows.win_powershell: + script: '{{ get_role_script }}' + register: to_tree_actual + +- name: assert promote to domain with pending reboot + assert: + that: + - to_tree is changed + - not to_tree.reboot_required + - to_tree_actual.output[0]["Domain"] == child_domain_name + - to_tree_actual.output[0]["DomainRole"] == "PrimaryDC" + - to_tree_actual.output[0]["HostName"] == new_hostname | upper + +- name: create tree domain - idempotent + domain_child: + dns_domain_name: '{{ child_domain_name }}' + parent_domain_name: '{{ domain_realm }}' + domain_type: tree + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + safe_mode_password: '{{ domain_password }}' + domain_mode: WinThreshold + database_path: C:\ansible_testing\DB + log_path: C:\ansible_testing\LogPath + sysvol_path: C:\ansible_testing\SysVol + reboot: true + register: to_tree_again + +- name: assert create tree domain - idempotent + assert: + that: + - not to_tree_again is changed + - not to_tree_again.reboot_required diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/test.yml b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/test.yml new file mode 100644 index 000000000..ba936e1d9 --- /dev/null +++ b/ansible_collections/microsoft/ad/tests/integration/targets/domain_child/test.yml @@ -0,0 +1,146 @@ +- name: ensure time is in sync + hosts: windows + gather_facts: false + tasks: + - name: get current host datetime + command: date +%s + changed_when: False + delegate_to: localhost + run_once: True + register: local_time + + - name: set datetime on Windows + ansible.windows.win_powershell: + parameters: + SecondsSinceEpoch: '{{ local_time.stdout | trim }}' + script: | + param($SecondsSinceEpoch) + + $utc = [System.DateTimeKind]::Utc + $epoch = New-Object -TypeName System.DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0, $utc + $date = $epoch.AddSeconds($SecondsSinceEpoch) + + Set-Date -Date $date + + - name: set common test vars + ansible.builtin.set_fact: + get_role_script: | + $Ansible.Changed = $false + Get-CimInstance -ClassName Win32_ComputerSystem -Property Domain, DomainRole, PartOfDomain | + Select-Object -Property @{ + N = 'Domain' + E = { + if ($_.PartOfDomain) { + $_.Domain + } + else { + $null + } + } + }, @{ + N = 'DomainRole' + E = { + switch ($_.DomainRole) { + 0 { "StandaloneWorkstation" } + 1 { "MemberWorkstation" } + 2 { "StandaloneServer" } + 3 { "MemberServer" } + 4 { "BackupDC" } + 5 { "PrimaryDC" } + } + } + }, @{ + N = 'HostName' + E = { $env:COMPUTERNAME } + } + +- name: run microsoft.ad.domain_child child tests + hosts: CHILD + gather_facts: false + + tasks: + - name: check domain status to see if test will run + ansible.windows.win_powershell: + script: '{{ get_role_script }}' + register: domain_status + + - ansible.builtin.include_tasks: tasks/main_child.yml + when: domain_status.output[0].Domain != child_domain_name + +- name: run microsoft.ad.domain_child tree tests + hosts: TREE + gather_facts: false + + tasks: + - name: check domain status to see if test will run + ansible.windows.win_powershell: + script: '{{ get_role_script }}' + register: domain_status + + - ansible.builtin.include_tasks: tasks/main_tree.yml + when: domain_status.output[0].Domain != child_domain_name + +- name: run extra tests to test out cross domain functionality in other modules + hosts: localhost + gather_facts: false + + tasks: + - name: create test OU in each domain + microsoft.ad.ou: + name: Ansible-{{ item }} + state: present + delegate_to: '{{ item }}' + register: ou_info + loop: + - PARENT + - CHILD + + - block: + - name: set facts for each OU DN + ansible.builtin.set_fact: + parent_ou: '{{ ou_info.results[0].distinguished_name }}' + child_ou: '{{ ou_info.results[1].distinguished_name }}' + + - name: create test users + microsoft.ad.user: + name: User-{{ item }} + state: present + password: '{{ domain_password }}' + path: '{{ {"PARENT": parent_ou, "CHILD": child_ou}[item] }}' + register: user_info + delegate_to: '{{ item }}' + loop: + - PARENT + - CHILD + + - name: create test groups + microsoft.ad.group: + name: Group-{{ item }} + state: present + path: '{{ {"PARENT": parent_ou, "CHILD": child_ou}[item] }}' + scope: universal + register: group_info + delegate_to: '{{ item }}' + loop: + - PARENT + - CHILD + + - name: set facts for each test user and group DN + ansible.builtin.set_fact: + parent_user: '{{ user_info.results[0].distinguished_name }}' + parent_group: '{{ group_info.results[0].distinguished_name }}' + child_user: '{{ user_info.results[1].distinguished_name }}' + child_group: '{{ group_info.results[1].distinguished_name }}' + + - name: run cross domain tests + ansible.builtin.import_tasks: tasks/cross_domain.yml + + always: + - name: remove test OU in each domain + microsoft.ad.ou: + name: Ansible-{{ item }} + state: absent + delegate_to: '{{ item }}' + loop: + - PARENT + - CHILD diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/group/tasks/tests.yml b/ansible_collections/microsoft/ad/tests/integration/targets/group/tasks/tests.yml index b40041b0d..958398a42 100644 --- a/ansible_collections/microsoft/ad/tests/integration/targets/group/tasks/tests.yml +++ b/ansible_collections/microsoft/ad/tests/integration/targets/group/tasks/tests.yml @@ -107,7 +107,8 @@ - my_user_2 - another-user register: fail_invalid_members - failed_when: 'fail_invalid_members.msg != "Failed to find the following ad objects for group members: ''fake-user'', ''another-user''"' + failed_when: >- + fail_invalid_members.msg != "Failed to find the AD object DNs for members.add. Invalid identities: 'fake-user', 'another-user'" - name: add members to a group - check group: @@ -141,7 +142,7 @@ members: add: - my_user_1 - - '{{ test_users.results[2].sid }}' + - name: '{{ test_users.results[2].sid }}' - MyGroup2-ReallyLongGroupNameHere register: add_member @@ -376,7 +377,8 @@ - my_user_2 - another-user register: fail_invalid_members - failed_when: 'fail_invalid_members.msg != "Failed to find the following ad objects for group members: ''fake-user'', ''another-user''"' + failed_when: >- + fail_invalid_members.msg != "Failed to find the AD object DNs for members.add. Invalid identities: 'fake-user', 'another-user'" - name: create group with custom options group: @@ -388,7 +390,8 @@ scope: domainlocal category: distribution homepage: www.ansible.com - managed_by: Domain Admins + managed_by: + name: Domain Admins members: add: - my_user_1 diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/membership/tasks/main.yml b/ansible_collections/microsoft/ad/tests/integration/targets/membership/tasks/main.yml index f66985da9..0060179e9 100644 --- a/ansible_collections/microsoft/ad/tests/integration/targets/membership/tasks/main.yml +++ b/ansible_collections/microsoft/ad/tests/integration/targets/membership/tasks/main.yml @@ -1,7 +1,7 @@ - set_fact: get_result_script: | $Ansible.Changed = $false - $cs = Get-CimInstance -ClassName Win32_ComputerSystem -Property Domain, PartOfDomain, Workgroup + $cs = Get-CimInstance -ClassName Win32_ComputerSystem -Property DNSHostName, Domain, PartOfDomain, Workgroup $domainName = if ($cs.PartOfDomain) { try { [System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().Name @@ -15,7 +15,8 @@ } [PSCustomObject]@{ - HostName = $env:COMPUTERNAME + HostName = $cs.DNSHostName + NetbiosName = $env:COMPUTERNAME PartOfDomain = $cs.PartOfDomain DnsDomainName = $domainName WorkgroupName = $cs.Workgroup @@ -23,8 +24,13 @@ get_ad_result_script: | $Ansible.Changed = $false - Get-ADComputer -Filter { Name -ne 'DC' } -Properties DistinguishedName, Name, Enabled | - Select-Object -Property DistinguishedName, Name, Enabled + Get-ADComputer -Filter { Name -ne 'DC' } -Properties DistinguishedName, DNSHostName, Name, Enabled | + Select-Object -Property @( + 'DistinguishedName' + @{ N = 'DNSHostName'; E = { $_.DNSHostName.Substring(0, $_.DNSHostName.IndexOf('.')) } } + 'Name' + 'Enabled' + ) - name: join domain invalid OU membership: @@ -65,6 +71,7 @@ - join_domain_check.reboot_required == False - join_domain_check_actual.output[0]["DnsDomainName"] == None - join_domain_check_actual.output[0]["HostName"] == "TEST" + - join_domain_check_actual.output[0]["NetbiosName"] == "TEST" - join_domain_check_actual.output[0]["PartOfDomain"] == False - join_domain_check_actual.output[0]["WorkgroupName"] == "WORKGROUP" @@ -95,9 +102,11 @@ - join_domain.reboot_required == False - join_domain_actual.output[0]["DnsDomainName"] == domain_realm - join_domain_actual.output[0]["HostName"] == "TEST" + - join_domain_actual.output[0]["NetbiosName"] == "TEST" - join_domain_actual.output[0]["PartOfDomain"] == True - join_domain_actual.output[0]["WorkgroupName"] == None - join_domain_ad_actual.output | length == 1 + - join_domain_ad_actual.output[0]["DNSHostName"] == "TEST" - join_domain_ad_actual.output[0]["Name"] == "TEST" - join_domain_ad_actual.output[0]["Enabled"] == True @@ -132,7 +141,7 @@ dns_domain_name: '{{ domain_realm }}' domain_admin_user: '{{ domain_user_upn }}' domain_admin_password: '{{ domain_password }}' - hostname: OTHER + hostname: TEST1-long-HOSTNAME1 state: domain reboot: true register: rename_host_domain_check @@ -156,9 +165,11 @@ - rename_host_domain_check.reboot_required == False - rename_host_domain_check_actual.output[0]["DnsDomainName"] == domain_realm - rename_host_domain_check_actual.output[0]["HostName"] == "TEST" + - rename_host_domain_check_actual.output[0]["NetbiosName"] == "TEST" - rename_host_domain_check_actual.output[0]["PartOfDomain"] == True - rename_host_domain_check_actual.output[0]["WorkgroupName"] == None - rename_host_domain_check_ad_actual.output | length == 1 + - rename_host_domain_check_ad_actual.output[0]["DNSHostName"] == "TEST" - rename_host_domain_check_ad_actual.output[0]["Name"] == "TEST" - rename_host_domain_check_ad_actual.output[0]["Enabled"] == True @@ -167,7 +178,7 @@ dns_domain_name: '{{ domain_realm }}' domain_admin_user: '{{ domain_user_upn }}' domain_admin_password: '{{ domain_password }}' - hostname: OTHER + hostname: TEST1-long-HOSTNAME1 state: domain reboot: true register: rename_host_domain @@ -183,19 +194,109 @@ delegate_to: DC register: rename_host_domain_ad_actual -- name: assert join domain +- name: assert rename hostname of domain joined host assert: that: - rename_host_domain is changed - rename_host_domain.reboot_required == False - rename_host_domain_actual.output[0]["DnsDomainName"] == domain_realm - - rename_host_domain_actual.output[0]["HostName"] == "OTHER" + - rename_host_domain_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME1" + - rename_host_domain_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" - rename_host_domain_actual.output[0]["PartOfDomain"] == True - rename_host_domain_actual.output[0]["WorkgroupName"] == None - rename_host_domain_ad_actual.output | length == 1 - - rename_host_domain_ad_actual.output[0]["Name"] == "OTHER" + - rename_host_domain_ad_actual.output[0]["DNSHostName"] == "TEST1-long-HOSTNAME1" + - rename_host_domain_ad_actual.output[0]["Name"] == "TEST1-LONG-HOST" - rename_host_domain_ad_actual.output[0]["Enabled"] == True +- name: rename hostname of domain joined host - idempotent + membership: + dns_domain_name: '{{ domain_realm }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + hostname: TEST1-long-HOSTNAME1 + state: domain + reboot: true + register: rename_host_domain_again + +- name: assert rename hostname of domain joined host - idempotent + assert: + that: + - not rename_host_domain_again is changed + +- name: rename hostname of domain joined host netbios portion - check mode + membership: + dns_domain_name: '{{ domain_realm }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + hostname: TEST2-long-HOSTNAME1 + state: domain + reboot: true + register: rename_host_domain_netbios_check + check_mode: True + +- name: get result of rename hostname of domain joined host netbios portion - check mode + ansible.windows.win_powershell: + script: '{{ get_result_script }}' + register: rename_host_domain_netbios_check_actual + +- name: get ad result of rename hostname of domain joined host netbios portion - check mode + ansible.windows.win_powershell: + script: '{{ get_ad_result_script }}' + delegate_to: DC + register: rename_host_domain_netbios_check_ad_actual + +- name: assert rename hostname of domain joined host netbios portion - check mode + assert: + that: + - rename_host_domain_netbios_check is changed + - rename_host_domain_netbios_check.reboot_required == False + - rename_host_domain_netbios_check_actual.output[0]["DnsDomainName"] == domain_realm + - rename_host_domain_netbios_check_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME1" + - rename_host_domain_netbios_check_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" + - rename_host_domain_netbios_check_actual.output[0]["PartOfDomain"] == True + - rename_host_domain_netbios_check_actual.output[0]["WorkgroupName"] == None + - rename_host_domain_netbios_check_ad_actual.output | length == 1 + - rename_host_domain_netbios_check_ad_actual.output[0]["DNSHostName"] == "TEST1-long-HOSTNAME1" + - rename_host_domain_netbios_check_ad_actual.output[0]["Name"] == "TEST1-LONG-HOST" + - rename_host_domain_netbios_check_ad_actual.output[0]["Enabled"] == True + +- name: rename hostname of domain joined host netbios portion + membership: + dns_domain_name: '{{ domain_realm }}' + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + hostname: TEST2-long-HOSTNAME1 + state: domain + reboot: true + register: rename_host_domain_netbios + +- name: get result of rename hostname of domain joined host netbios portion + ansible.windows.win_powershell: + script: '{{ get_result_script }}' + register: rename_host_domain_netbios_actual + +- name: get ad result of rename hostname of domain joined host netbios portion + ansible.windows.win_powershell: + script: '{{ get_ad_result_script }}' + delegate_to: DC + register: rename_host_domain_netbios_ad_actual + +- name: assert rename hostname of domain joined host + assert: + that: + - rename_host_domain_netbios is changed + - rename_host_domain_netbios.reboot_required == False + - rename_host_domain_netbios_actual.output[0]["DnsDomainName"] == domain_realm + - rename_host_domain_netbios_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME1" + - rename_host_domain_netbios_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" + - rename_host_domain_netbios_actual.output[0]["PartOfDomain"] == True + - rename_host_domain_netbios_actual.output[0]["WorkgroupName"] == None + - rename_host_domain_netbios_ad_actual.output | length == 1 + - rename_host_domain_netbios_ad_actual.output[0]["DNSHostName"] == "TEST2-long-HOSTNAME1" + - rename_host_domain_netbios_ad_actual.output[0]["Name"] == "TEST2-LONG-HOST" + - rename_host_domain_netbios_ad_actual.output[0]["Enabled"] == True + - name: change domain to workgroup - check mode membership: workgroup_name: TEST @@ -222,11 +323,13 @@ - to_workgroup_check is changed - to_workgroup_check.reboot_required == True - to_workgroup_check_actual.output[0]["DnsDomainName"] == domain_realm - - to_workgroup_check_actual.output[0]["HostName"] == "OTHER" + - to_workgroup_check_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME1" + - to_workgroup_check_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" - to_workgroup_check_actual.output[0]["PartOfDomain"] == True - to_workgroup_check_actual.output[0]["WorkgroupName"] == None - to_workgroup_check_ad_actual.output | length == 1 - - to_workgroup_check_ad_actual.output[0]["Name"] == "OTHER" + - to_workgroup_check_ad_actual.output[0]["DNSHostName"] == "TEST2-long-HOSTNAME1" + - to_workgroup_check_ad_actual.output[0]["Name"] == "TEST2-LONG-HOST" - to_workgroup_check_ad_actual.output[0]["Enabled"] == True - name: change domain to workgroup @@ -238,7 +341,7 @@ register: to_workgroup - set_fact: - local_user: OTHER\{{ ansible_user }} + local_user: TEST2-LONG-HOST\{{ ansible_user }} - ansible.windows.win_reboot: when: to_workgroup.reboot_required @@ -266,16 +369,18 @@ - to_workgroup is changed - to_workgroup.reboot_required == True - to_workgroup_actual.output[0]["DnsDomainName"] == None - - to_workgroup_actual.output[0]["HostName"] == "OTHER" + - to_workgroup_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME1" + - to_workgroup_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" - to_workgroup_actual.output[0]["PartOfDomain"] == False - to_workgroup_actual.output[0]["WorkgroupName"] == "TEST" - to_workgroup_ad_actual.output | length == 1 - - to_workgroup_ad_actual.output[0]["Name"] == "OTHER" + - to_workgroup_ad_actual.output[0]["DNSHostName"] == "TEST2-long-HOSTNAME1" + - to_workgroup_ad_actual.output[0]["Name"] == "TEST2-LONG-HOST" - to_workgroup_ad_actual.output[0]["Enabled"] == False - name: remove orphaned AD account for later tests microsoft.ad.computer: - name: OTHER + name: TEST2-LONG-HOST state: absent delegate_to: DC @@ -315,7 +420,8 @@ - change_workgroup_check is changed - change_workgroup_check.reboot_required == False - change_workgroup_check_actual.output[0]["DnsDomainName"] == None - - change_workgroup_check_actual.output[0]["HostName"] == "OTHER" + - change_workgroup_check_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME1" + - change_workgroup_check_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" - change_workgroup_check_actual.output[0]["PartOfDomain"] == False - change_workgroup_check_actual.output[0]["WorkgroupName"] == "TEST" @@ -339,7 +445,8 @@ - change_workgroup is changed - change_workgroup.reboot_required == False - change_workgroup_actual.output[0]["DnsDomainName"] == None - - change_workgroup_actual.output[0]["HostName"] == "OTHER" + - change_workgroup_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME1" + - change_workgroup_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" - change_workgroup_actual.output[0]["PartOfDomain"] == False - change_workgroup_actual.output[0]["WorkgroupName"] == "TEST2" @@ -350,7 +457,7 @@ domain_admin_password: '{{ domain_password }}' state: workgroup reboot: true - hostname: FOO + hostname: TEST1-long-HOSTNAME2 register: change_hostname_check check_mode: true @@ -365,7 +472,8 @@ - change_hostname_check is changed - change_hostname_check.reboot_required == False - change_hostname_check_actual.output[0]["DnsDomainName"] == None - - change_hostname_check_actual.output[0]["HostName"] == "OTHER" + - change_hostname_check_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME1" + - change_hostname_check_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" - change_hostname_check_actual.output[0]["PartOfDomain"] == False - change_hostname_check_actual.output[0]["WorkgroupName"] == "TEST2" @@ -376,7 +484,7 @@ domain_admin_password: '{{ domain_password }}' state: workgroup reboot: true - hostname: FOO + hostname: TEST1-long-HOSTNAME2 register: change_hostname - name: get result of change just the hostname @@ -384,16 +492,85 @@ script: '{{ get_result_script }}' register: change_hostname_actual -- name: assert change just the hostname - check mode +- name: assert change just the hostname assert: that: - change_hostname is changed - change_hostname.reboot_required == False - change_hostname_actual.output[0]["DnsDomainName"] == None - - change_hostname_actual.output[0]["HostName"] == "FOO" + - change_hostname_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME2" + - change_hostname_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" - change_hostname_actual.output[0]["PartOfDomain"] == False - change_hostname_actual.output[0]["WorkgroupName"] == "TEST2" +- name: change just the hostname - idempotent + membership: + workgroup_name: TEST2 + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + state: workgroup + reboot: true + hostname: TEST1-long-HOSTNAME2 + register: change_hostname_again + +- name: assert change just the hostname - idempotent + assert: + that: + - not change_hostname_again is changed + +- name: change just the hostname netbios portion - check mode + membership: + workgroup_name: TEST2 + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + state: workgroup + reboot: true + hostname: TEST2-long-HOSTNAME2 + register: change_hostname_netbios_check + check_mode: true + +- name: get result of change just the hostname netbios portion - check mode + ansible.windows.win_powershell: + script: '{{ get_result_script }}' + register: change_hostname_netbios_check_actual + +- name: assert change just the hostname netbios portion - check mode + assert: + that: + - change_hostname_netbios_check is changed + - change_hostname_netbios_check.reboot_required == False + - change_hostname_netbios_check_actual.output[0]["DnsDomainName"] == None + - change_hostname_netbios_check_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME2" + - change_hostname_netbios_check_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" + - change_hostname_netbios_check_actual.output[0]["PartOfDomain"] == False + - change_hostname_netbios_check_actual.output[0]["WorkgroupName"] == "TEST2" + +- name: change just the hostname netbios portion + membership: + workgroup_name: TEST2 + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + state: workgroup + reboot: true + hostname: TEST2-long-HOSTNAME2 + register: change_hostname_netbios + +- name: get result of change just the hostname netbios portion + ansible.windows.win_powershell: + script: '{{ get_result_script }}' + register: change_hostname_netbios_actual + +- name: assert change just the hostname + assert: + that: + - change_hostname_netbios is changed + - change_hostname_netbios.reboot_required == False + - change_hostname_netbios_actual.output[0]["DnsDomainName"] == None + - change_hostname_netbios_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME2" + - change_hostname_netbios_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" + - change_hostname_netbios_actual.output[0]["PartOfDomain"] == False + - change_hostname_netbios_actual.output[0]["WorkgroupName"] == "TEST2" + - name: create custom OU ansible.windows.win_powershell: script: | @@ -407,7 +584,7 @@ dns_domain_name: '{{ domain_realm }}' domain_admin_user: '{{ domain_user_upn }}' domain_admin_password: '{{ domain_password }}' - hostname: BAR + hostname: TEST1-long-HOSTNAME3 domain_ou_path: '{{ custom_ou.output[0] }}' state: domain register: join_ou_check @@ -424,7 +601,8 @@ - join_ou_check is changed - join_ou_check.reboot_required == True - join_ou_check_actual.output[0]["DnsDomainName"] == None - - join_ou_check_actual.output[0]["HostName"] == "FOO" + - join_ou_check_actual.output[0]["HostName"] == "TEST2-long-HOSTNAME2" + - join_ou_check_actual.output[0]["NetbiosName"] == "TEST2-LONG-HOST" - join_ou_check_actual.output[0]["PartOfDomain"] == False - join_ou_check_actual.output[0]["WorkgroupName"] == "TEST2" @@ -433,7 +611,7 @@ dns_domain_name: '{{ domain_realm }}' domain_admin_user: '{{ domain_user_upn }}' domain_admin_password: '{{ domain_password }}' - hostname: BAR + hostname: TEST1-long-HOSTNAME3 domain_ou_path: '{{ custom_ou.output[0] }}' state: domain register: join_ou @@ -452,26 +630,28 @@ register: join_ou_ad_actual delegate_to: DC -- name: assert change just the hostname +- name: assert join domain with hostname and OUT assert: that: - join_ou is changed - join_ou.reboot_required == True - join_ou_actual.output[0]["DnsDomainName"] == domain_realm - - join_ou_actual.output[0]["HostName"] == "BAR" + - join_ou_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME3" + - join_ou_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" - join_ou_actual.output[0]["PartOfDomain"] == True - join_ou_actual.output[0]["WorkgroupName"] == None - join_ou_ad_actual.output | length == 1 - - join_ou_ad_actual.output[0]["Name"] == "BAR" + - join_ou_ad_actual.output[0]["DNSHostName"] == "TEST1-long-HOSTNAME3" + - join_ou_ad_actual.output[0]["Name"] == "TEST1-LONG-HOST" - join_ou_ad_actual.output[0]["Enabled"] == True - - join_ou_ad_actual.output[0]["DistinguishedName"] == "CN=BAR," ~ custom_ou.output[0] + - join_ou_ad_actual.output[0]["DistinguishedName"] == "CN=TEST1-LONG-HOST," ~ custom_ou.output[0] - name: change domain to workgroup with hostname change - check mode membership: workgroup_name: WORKGROUP domain_admin_user: '{{ domain_user_upn }}' domain_admin_password: '{{ domain_password }}' - hostname: FOO + hostname: TEST1-long-HOSTNAME4 state: workgroup register: to_workgroup_hostname_check check_mode: true @@ -493,11 +673,13 @@ - to_workgroup_hostname_check is changed - to_workgroup_hostname_check.reboot_required == True - to_workgroup_hostname_check_actual.output[0]["DnsDomainName"] == domain_realm - - to_workgroup_hostname_check_actual.output[0]["HostName"] == "BAR" + - to_workgroup_hostname_check_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME3" + - to_workgroup_hostname_check_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" - to_workgroup_hostname_check_actual.output[0]["PartOfDomain"] == True - to_workgroup_hostname_check_actual.output[0]["WorkgroupName"] == None - to_workgroup_hostname_check_ad_actual.output | length == 1 - - to_workgroup_hostname_check_ad_actual.output[0]["Name"] == "BAR" + - to_workgroup_hostname_check_ad_actual.output[0]["DNSHostName"] == "TEST1-long-HOSTNAME3" + - to_workgroup_hostname_check_ad_actual.output[0]["Name"] == "TEST1-LONG-HOST" - to_workgroup_hostname_check_ad_actual.output[0]["Enabled"] == True - name: change domain to workgroup with hostname change @@ -505,7 +687,7 @@ workgroup_name: WORKGROUP domain_admin_user: '{{ domain_user_upn }}' domain_admin_password: '{{ domain_password }}' - hostname: FOO + hostname: TEST1-long-HOSTNAME4 state: workgroup reboot: true register: to_workgroup_hostname @@ -527,13 +709,30 @@ - to_workgroup_hostname is changed - to_workgroup_hostname.reboot_required == False - to_workgroup_hostname_actual.output[0]["DnsDomainName"] == None - - to_workgroup_hostname_actual.output[0]["HostName"] == "FOO" + - to_workgroup_hostname_actual.output[0]["HostName"] == "TEST1-long-HOSTNAME4" + - to_workgroup_hostname_actual.output[0]["NetbiosName"] == "TEST1-LONG-HOST" - to_workgroup_hostname_actual.output[0]["PartOfDomain"] == False - to_workgroup_hostname_actual.output[0]["WorkgroupName"] == "WORKGROUP" - to_workgroup_hostname_ad_actual.output | length == 1 - - to_workgroup_hostname_ad_actual.output[0]["Name"] == "BAR" + - to_workgroup_hostname_ad_actual.output[0]["DNSHostName"] == "TEST1-long-HOSTNAME3" + - to_workgroup_hostname_ad_actual.output[0]["Name"] == "TEST1-LONG-HOST" - to_workgroup_hostname_ad_actual.output[0]["Enabled"] == False +- name: change domain to workgroup with hostname change - idempotent + membership: + workgroup_name: WORKGROUP + domain_admin_user: '{{ domain_user_upn }}' + domain_admin_password: '{{ domain_password }}' + hostname: TEST1-long-HOSTNAME4 + state: workgroup + reboot: true + register: to_workgroup_hostname_again + +- name: assert change domain to workgroup with hostname change - idempotent + assert: + that: + - not to_workgroup_hostname_again is changed + - name: remove orphaned AD account for later tests microsoft.ad.computer: name: BAR diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/ou/tasks/tests.yml b/ansible_collections/microsoft/ad/tests/integration/targets/ou/tasks/tests.yml index 49d06aefb..b6061b7d5 100644 --- a/ansible_collections/microsoft/ad/tests/integration/targets/ou/tasks/tests.yml +++ b/ansible_collections/microsoft/ad/tests/integration/targets/ou/tasks/tests.yml @@ -163,7 +163,8 @@ country: US description: Custom description display_name: OU display Name - managed_by: Domain Users + managed_by: + name: Domain Users postal_code: 10001 state_province: '' street: Main diff --git a/ansible_collections/microsoft/ad/tests/integration/targets/user/tasks/tests.yml b/ansible_collections/microsoft/ad/tests/integration/targets/user/tasks/tests.yml index 98718da6f..10261afdf 100644 --- a/ansible_collections/microsoft/ad/tests/integration/targets/user/tasks/tests.yml +++ b/ansible_collections/microsoft/ad/tests/integration/targets/user/tasks/tests.yml @@ -510,6 +510,7 @@ user: name: MyUser state: present + account_locked: False city: Brisbane company: Red Hat country: au @@ -563,6 +564,7 @@ user: name: MyUser state: present + account_locked: False city: Brisbane company: Red Hat country: au @@ -685,6 +687,7 @@ user: name: MyUser state: present + account_locked: False city: Brisbane company: Red Hat country: au @@ -1095,7 +1098,8 @@ - Invalid register: fail_missing_group failed_when: - - '"Failed to locate group Invalid: Cannot find an object with identity" not in fail_missing_group.msg' + - >- + "Failed to find the AD object DNs for groups.add. Invalid identities: 'Invalid'" not in fail_missing_group.msg - name: warn on group that is missing user: @@ -1104,7 +1108,7 @@ groups: add: - Invalid - missing_behaviour: warn + lookup_failure_action: warn register: warn_missing_group - name: assert warn on group that is missing @@ -1112,7 +1116,8 @@ that: - not warn_missing_group is changed - warn_missing_group.warnings | length == 1 - - '"Failed to locate group Invalid but continuing on" in warn_missing_group.warnings[0]' + - >- + "Failed to find the AD object DNs for groups.add. Ignoring invalid identities: 'Invalid'" in warn_missing_group.warnings[0] - name: ignore on group that is missing user: @@ -1120,7 +1125,7 @@ path: '{{ setup_domain_info.output[0].defaultNamingContext }}' groups: add: - - Invalid + - name: Invalid missing_behaviour: ignore register: ignore_missing_group @@ -1136,7 +1141,7 @@ path: '{{ setup_domain_info.output[0].defaultNamingContext }}' groups: remove: - - domain admins + - name: domain admins - Enterprise Admins register: groups_remove |