From e555358c323dd473db91ad81c30f2f3aa0ad0270 Mon Sep 17 00:00:00 2001 From: Matt Martz Date: Mon, 2 Nov 2020 17:00:17 -0600 Subject: [PATCH] Remove incidental vmware tests (#72420) * Add explicit tests for ansible.module_utils.common.network.is_mac * Test missing ANSIBLE_CONFIG * Add explicit inventory script tests * Add explicit tests for _consume_options * Adjust perms, remove extra file * ci_complete ci_coverage * remove incidental_inventory_vmware_vm_inventory * ci_complete ci_coverage * Remove incidental_script_inventory_vmware_inventory * ci_complete ci_coverage * Remove incidental_vmware_guest * ci_complete ci_coverage * Remove incidental_vmware_host_hyperthreading and incidental_vmware_prepare_tests * ci_complete ci_coverage * newline and comment about what the test is doing * ci_complete ci_coverage (cherry picked from commit ccc63abc8ed8b7f7a3e5be436ccde57239a58a1d) --- shippable.yml | 1 - .../targets/common_network/aliases | 1 + .../targets/common_network/tasks/main.yml | 4 + .../common_network/test_plugins/is_mac.py | 14 + test/integration/targets/config/runme.sh | 10 +- .../aliases | 3 - .../ansible.cfg | 8 - .../runme.sh | 83 - .../test_vmware_vm_inventory.yml | 24 - .../aliases | 3 - .../runme.sh | 58 - .../test_vmware_inventory.yml | 18 - .../vmware_inventory.ini | 127 - .../vmware_inventory.py | 793 ----- .../vmware_inventory.sh | 3 - .../targets/incidental_vmware_guest/aliases | 3 - .../incidental_vmware_guest/defaults/main.yml | 33 - .../tasks/boot_firmware_d1_c1_f0.yml | 117 - .../tasks/cdrom_d1_c1_f0.yml | 269 -- .../tasks/check_mode.yml | 60 - .../tasks/clone_customize_guest_test.yml | 47 - .../tasks/clone_d1_c1_f0.yml | 101 - .../tasks/clone_resize_disks.yml | 77 - .../tasks/clone_with_convert.yml | 66 - .../tasks/create_d1_c1_f0.yml | 164 - .../tasks/create_guest_invalid_d1_c1_f0.yml | 32 - .../tasks/create_nw_d1_c1_f0.yml | 38 - .../tasks/create_rp_d1_c1_f0.yml | 205 -- .../tasks/delete_vm.yml | 22 - .../tasks/disk_mode_d1_c1_f0.yml | 89 - .../tasks/disk_size_d1_c1_f0.yml | 31 - .../tasks/disk_type_d1_c1_f0.yml | 33 - .../tasks/linked_clone_d1_c1_f0.yml | 100 - .../tasks/mac_address_d1_c1_f0.yml | 37 - .../incidental_vmware_guest/tasks/main.yml | 19 - .../tasks/max_connections.yml | 45 - .../tasks/mem_reservation.yml | 125 - .../tasks/network_negative_test.yml | 339 -- .../tasks/network_with_device.yml | 60 - .../tasks/network_with_dvpg.yml | 152 - .../tasks/network_with_portgroup.yml | 47 - .../tasks/non_existent_vm_ops.yml | 23 - .../tasks/poweroff_d1_c1_f0.yml | 27 - .../tasks/poweroff_d1_c1_f1.yml | 22 - .../tasks/reconfig_vm_to_latest_version.yml | 73 - .../tasks/remove_vm_from_inventory.yml | 61 - .../tasks/run_test_playbook.yml | 17 - .../tasks/template_d1_c1_f0.yml | 105 - .../tasks/vapp_d1_c1_f0.yml | 100 - .../tasks/windows_vbs_d1_c1_f0.yml | 93 - .../aliases | 3 - .../tasks/main.yml | 92 - .../incidental_vmware_prepare_tests/aliases | 1 - .../meta/main.yml | 2 - .../tasks/init_real_lab.yml | 29 - .../tasks/init_vcsim.yml | 48 - .../tasks/main.yml | 25 - .../tasks/setup_attach_hosts.yml | 30 - .../tasks/setup_category.yml | 5 - .../tasks/setup_cluster.yml | 10 - .../tasks/setup_content_library.yml | 7 - .../tasks/setup_datacenter.yml | 11 - .../tasks/setup_datastore.yml | 42 - .../tasks/setup_dvs_portgroup.yml | 18 - .../tasks/setup_dvswitch.yml | 20 - .../tasks/setup_resource_pool.yml | 15 - .../tasks/setup_switch.yml | 7 - .../tasks/setup_tag.yml | 15 - .../tasks/setup_virtualmachines.yml | 46 - .../tasks/teardown.yml | 24 - .../tasks/teardown_with_esxi.yml | 96 - .../vars/common.yml | 12 - .../vars/vcenter_1esxi.yml | 33 - .../vars/vcenter_2esxi.yml | 34 - .../vars/vcenter_only.yml | 6 - .../vars/vcsim.yml | 19 - .../targets/inventory_script/aliases | 1 + .../targets/inventory_script/inventory.json | 1045 ++++++ .../targets/inventory_script/inventory.sh | 7 + .../targets/inventory_script/runme.sh | 5 + .../test_inventory.py | 3 +- .../plugins/inventory/vmware_vm_inventory.py | 477 --- .../plugins/module_utils/vmware.py | 1630 --------- .../plugins/modules/vmware_guest.py | 2914 ----------------- .../modules/vmware_host_hyperthreading.py | 261 -- 85 files changed, 1085 insertions(+), 9890 deletions(-) create mode 100644 test/integration/targets/common_network/aliases create mode 100644 test/integration/targets/common_network/tasks/main.yml create mode 100644 test/integration/targets/common_network/test_plugins/is_mac.py delete mode 100644 test/integration/targets/incidental_inventory_vmware_vm_inventory/aliases delete mode 100644 test/integration/targets/incidental_inventory_vmware_vm_inventory/ansible.cfg delete mode 100755 test/integration/targets/incidental_inventory_vmware_vm_inventory/runme.sh delete mode 100644 test/integration/targets/incidental_inventory_vmware_vm_inventory/test_vmware_vm_inventory.yml delete mode 100644 test/integration/targets/incidental_script_inventory_vmware_inventory/aliases delete mode 100755 test/integration/targets/incidental_script_inventory_vmware_inventory/runme.sh delete mode 100644 test/integration/targets/incidental_script_inventory_vmware_inventory/test_vmware_inventory.yml delete mode 100644 test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.ini delete mode 100755 test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.py delete mode 100755 test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.sh delete mode 100644 test/integration/targets/incidental_vmware_guest/aliases delete mode 100644 test/integration/targets/incidental_vmware_guest/defaults/main.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/boot_firmware_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/cdrom_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/check_mode.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/clone_customize_guest_test.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/clone_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/clone_resize_disks.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/clone_with_convert.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/create_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/create_guest_invalid_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/create_nw_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/create_rp_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/delete_vm.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/disk_mode_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/disk_size_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/disk_type_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/linked_clone_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/mac_address_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/main.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/max_connections.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/mem_reservation.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/network_negative_test.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/network_with_device.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/network_with_dvpg.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/network_with_portgroup.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/non_existent_vm_ops.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f1.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/reconfig_vm_to_latest_version.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/remove_vm_from_inventory.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/run_test_playbook.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/template_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/vapp_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_guest/tasks/windows_vbs_d1_c1_f0.yml delete mode 100644 test/integration/targets/incidental_vmware_host_hyperthreading/aliases delete mode 100644 test/integration/targets/incidental_vmware_host_hyperthreading/tasks/main.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/aliases delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/meta/main.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/init_real_lab.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/init_vcsim.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/main.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_attach_hosts.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_category.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_cluster.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_content_library.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datacenter.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datastore.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvs_portgroup.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvswitch.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_resource_pool.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_switch.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_tag.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_virtualmachines.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown_with_esxi.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/vars/common.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_1esxi.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_2esxi.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_only.yml delete mode 100644 test/integration/targets/incidental_vmware_prepare_tests/vars/vcsim.yml create mode 100644 test/integration/targets/inventory_script/aliases create mode 100644 test/integration/targets/inventory_script/inventory.json create mode 100755 test/integration/targets/inventory_script/inventory.sh create mode 100755 test/integration/targets/inventory_script/runme.sh delete mode 100644 test/support/integration/plugins/inventory/vmware_vm_inventory.py delete mode 100644 test/support/integration/plugins/module_utils/vmware.py delete mode 100644 test/support/integration/plugins/modules/vmware_guest.py delete mode 100644 test/support/integration/plugins/modules/vmware_host_hyperthreading.py diff --git a/shippable.yml b/shippable.yml index eb449a354f1..63ce28d199d 100644 --- a/shippable.yml +++ b/shippable.yml @@ -136,7 +136,6 @@ matrix: - env: T=i/aws/3.6/1 - env: T=i/azure/2.7/1 - env: T=i/azure/3.6/1 - - env: T=i/vcenter//1 - env: T=i/tower//1 - env: T=i/cloud//1 diff --git a/test/integration/targets/common_network/aliases b/test/integration/targets/common_network/aliases new file mode 100644 index 00000000000..70a7b7a9f32 --- /dev/null +++ b/test/integration/targets/common_network/aliases @@ -0,0 +1 @@ +shippable/posix/group5 diff --git a/test/integration/targets/common_network/tasks/main.yml b/test/integration/targets/common_network/tasks/main.yml new file mode 100644 index 00000000000..97b3dd0d402 --- /dev/null +++ b/test/integration/targets/common_network/tasks/main.yml @@ -0,0 +1,4 @@ +- assert: + that: + - '"00:00:00:a1:2b:cc" is is_mac' + - '"foo" is not is_mac' diff --git a/test/integration/targets/common_network/test_plugins/is_mac.py b/test/integration/targets/common_network/test_plugins/is_mac.py new file mode 100644 index 00000000000..6a4d4092cd6 --- /dev/null +++ b/test/integration/targets/common_network/test_plugins/is_mac.py @@ -0,0 +1,14 @@ +# Copyright: (c) 2020, Matt Martz +# 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 + +from ansible.module_utils.common.network import is_mac + + +class TestModule(object): + def tests(self): + return { + 'is_mac': is_mac, + } diff --git a/test/integration/targets/config/runme.sh b/test/integration/targets/config/runme.sh index c7fe01420c7..73c3778b47a 100755 --- a/test/integration/targets/config/runme.sh +++ b/test/integration/targets/config/runme.sh @@ -9,7 +9,9 @@ ANSIBLE_TIMEOUT= ansible -m ping testhost -i ../../inventory "$@" # env var is wrong type, this should be a fatal error pointing at the setting ANSIBLE_TIMEOUT='lola' ansible -m ping testhost -i ../../inventory "$@" 2>&1|grep 'Invalid type for configuration option setting: DEFAULT_TIMEOUT' -# https://github.com/ansible/ansible/issues/69577 -ANSIBLE_REMOTE_TMP="$HOME/.ansible/directory_with_no_space" ansible -m ping testhost -i ../../inventory "$@" - -ANSIBLE_REMOTE_TMP="$HOME/.ansible/directory with space" ansible -m ping testhost -i ../../inventory "$@" \ No newline at end of file +# https://github.com/ansible/ansible/issues/69577 +ANSIBLE_REMOTE_TMP="$HOME/.ansible/directory_with_no_space" ansible -m ping testhost -i ../../inventory "$@" + +ANSIBLE_REMOTE_TMP="$HOME/.ansible/directory with space" ansible -m ping testhost -i ../../inventory "$@" + +ANSIBLE_CONFIG=nonexistent.cfg ansible-config dump --only-changed -v | grep 'No config file found; using defaults' diff --git a/test/integration/targets/incidental_inventory_vmware_vm_inventory/aliases b/test/integration/targets/incidental_inventory_vmware_vm_inventory/aliases deleted file mode 100644 index 420e0cddd5c..00000000000 --- a/test/integration/targets/incidental_inventory_vmware_vm_inventory/aliases +++ /dev/null @@ -1,3 +0,0 @@ -shippable/vcenter/incidental -cloud/vcenter -destructive diff --git a/test/integration/targets/incidental_inventory_vmware_vm_inventory/ansible.cfg b/test/integration/targets/incidental_inventory_vmware_vm_inventory/ansible.cfg deleted file mode 100644 index 158f5849fa0..00000000000 --- a/test/integration/targets/incidental_inventory_vmware_vm_inventory/ansible.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[defaults] -inventory = test-config.vmware.yaml - -[inventory] -enable_plugins = vmware_vm_inventory -cache = True -cache_plugin = jsonfile -cache_connection = inventory_cache diff --git a/test/integration/targets/incidental_inventory_vmware_vm_inventory/runme.sh b/test/integration/targets/incidental_inventory_vmware_vm_inventory/runme.sh deleted file mode 100755 index e220624a59d..00000000000 --- a/test/integration/targets/incidental_inventory_vmware_vm_inventory/runme.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bash - -[[ -n "$DEBUG" || -n "$ANSIBLE_DEBUG" ]] && set -x - -set -euo pipefail - -# Required to differentiate between Python 2 and 3 environ -PYTHON=${ANSIBLE_TEST_PYTHON_INTERPRETER:-python} - -export ANSIBLE_CONFIG=ansible.cfg -export VMWARE_SERVER="${VCENTER_HOSTNAME}" -export VMWARE_USERNAME="${VCENTER_USERNAME}" -export VMWARE_PASSWORD="${VCENTER_PASSWORD}" -port=5000 -VMWARE_CONFIG=test-config.vmware.yaml -inventory_cache="$(pwd)/inventory_cache" - -cat > "$VMWARE_CONFIG" < /dev/null 2>&1 - -echo "Start new VCSIM server" -curl "http://${VCENTER_HOSTNAME}:${port}/spawn?datacenter=1&cluster=1&folder=0" > /dev/null 2>&1 - -echo "Debugging new instances" -curl "http://${VCENTER_HOSTNAME}:${port}/govc_find" - -# Get inventory -ansible-inventory -i ${VMWARE_CONFIG} --list - -echo "Check if cache is working for inventory plugin" -if [ ! -n "$(find "${inventory_cache}" -maxdepth 1 -name 'vmware_vm_inventory_*' -print -quit)" ]; then - echo "Cache directory not found. Please debug" - exit 1 -fi -echo "Cache is working" - -# Get inventory using YAML -ansible-inventory -i ${VMWARE_CONFIG} --list --yaml - -# Install TOML for --toml -${PYTHON} -m pip freeze | grep toml > /dev/null 2>&1 -TOML_TEST_RESULT=$? -if [ $TOML_TEST_RESULT -ne 0 ]; then - echo "Installing TOML package" - ${PYTHON} -m pip install toml -else - echo "TOML package already exists, skipping installation" -fi - -# Get inventory using TOML -ansible-inventory -i ${VMWARE_CONFIG} --list --toml -TOML_INVENTORY_LIST_RESULT=$? -if [ $TOML_INVENTORY_LIST_RESULT -ne 0 ]; then - echo "Inventory plugin failed to list inventory host using --toml, please debug" - exit 1 -fi - -# Test playbook with given inventory -ansible-playbook -i ${VMWARE_CONFIG} test_vmware_vm_inventory.yml --connection=local "$@" diff --git a/test/integration/targets/incidental_inventory_vmware_vm_inventory/test_vmware_vm_inventory.yml b/test/integration/targets/incidental_inventory_vmware_vm_inventory/test_vmware_vm_inventory.yml deleted file mode 100644 index 88e2be9bd1a..00000000000 --- a/test/integration/targets/incidental_inventory_vmware_vm_inventory/test_vmware_vm_inventory.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Test code for the vmware guest dynamic plugin module -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - ---- -- name: Test VMware Guest Dynamic Inventroy Plugin - hosts: localhost - tasks: - - name: store the vcenter container ip - set_fact: - vcsim: "{{ lookup('env', 'VCENTER_HOSTNAME') }}" - - - name: Check that there are 'all' and 'otherGuest' groups present in inventory - assert: - that: "'{{ item }}' in {{ groups.keys() | list }}" - with_items: - - all - - otherGuest - - - name: Check if Hostname and other details are populated in hostvars - assert: - that: - - hostvars[item].name is defined - with_items: "{{ groups['all'] }}" diff --git a/test/integration/targets/incidental_script_inventory_vmware_inventory/aliases b/test/integration/targets/incidental_script_inventory_vmware_inventory/aliases deleted file mode 100644 index 420e0cddd5c..00000000000 --- a/test/integration/targets/incidental_script_inventory_vmware_inventory/aliases +++ /dev/null @@ -1,3 +0,0 @@ -shippable/vcenter/incidental -cloud/vcenter -destructive diff --git a/test/integration/targets/incidental_script_inventory_vmware_inventory/runme.sh b/test/integration/targets/incidental_script_inventory_vmware_inventory/runme.sh deleted file mode 100755 index d0d6cd540b3..00000000000 --- a/test/integration/targets/incidental_script_inventory_vmware_inventory/runme.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash - -[[ -n "$DEBUG" || -n "$ANSIBLE_DEBUG" ]] && set -x - -set -euo pipefail - -contrib_dir=$(pwd) - -echo "DEBUG: using ${contrib_dir}" - -export ANSIBLE_CONFIG=ansible.cfg -export VMWARE_SERVER="${VCENTER_HOSTNAME}" -export VMWARE_USERNAME="${VCENTER_USERNAME}" -export VMWARE_PASSWORD="${VCENTER_PASSWORD}" - -VMWARE_CONFIG=${contrib_dir}/vmware_inventory.ini - - -trap cleanup INT TERM EXIT - -# Remove default inventory config file -if [ -f "${VMWARE_CONFIG}" ]; -then - echo "DEBUG: Creating backup of ${VMWARE_CONFIG}" - cp "${VMWARE_CONFIG}" "${VMWARE_CONFIG}.bk" -fi - -cat > "${VMWARE_CONFIG}" < /dev/null 2>&1 - -echo "Start new VCSIM server" -curl "http://${VCENTER_HOSTNAME}:5000/spawn?datacenter=1&cluster=1&folder=0" > /dev/null 2>&1 - -echo "Debugging new instances" -curl "http://${VCENTER_HOSTNAME}:5000/govc_find" - -# Get inventory -ansible-playbook -i ./vmware_inventory.sh "./test_vmware_inventory.yml" --connection=local "$@" - -echo "DEBUG: Done" diff --git a/test/integration/targets/incidental_script_inventory_vmware_inventory/test_vmware_inventory.yml b/test/integration/targets/incidental_script_inventory_vmware_inventory/test_vmware_inventory.yml deleted file mode 100644 index 035d1d16ece..00000000000 --- a/test/integration/targets/incidental_script_inventory_vmware_inventory/test_vmware_inventory.yml +++ /dev/null @@ -1,18 +0,0 @@ -# Test code for the vmware guest contrib inventory -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - ---- -- name: Test VMware guest contrib inventroy script - hosts: localhost - tasks: - - name: store the vcenter container ip - set_fact: - vcsim: "{{ lookup('env', 'VCENTER_HOSTNAME') }}" - - - name: Check that groups present in inventory - assert: - that: - - "'{{item}}' in groups" - with_items: - - all diff --git a/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.ini b/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.ini deleted file mode 100644 index f94570f8910..00000000000 --- a/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.ini +++ /dev/null @@ -1,127 +0,0 @@ -# Ansible VMware external inventory script settings - -[vmware] - -# The resolvable hostname or ip address of the vsphere -server=vcenter - -# The port for the vsphere API -#port=443 - -# The username with access to the vsphere API. This setting -# may also be defined via the VMWARE_USERNAME environment variable. -username=administrator@vsphere.local - -# The password for the vsphere API. This setting -# may also be defined via the VMWARE_PASSWORD environment variable. -password=vmware - -# Verify the server's SSL certificate -#validate_certs = True - -# Specify the number of seconds to use the inventory cache before it is -# considered stale. If not defined, defaults to 0 seconds. -#cache_max_age = 3600 - - -# Specify the directory used for storing the inventory cache. If not defined, -# caching will be disabled. -#cache_path = ~/.cache/ansible - - -# Max object level refers to the level of recursion the script will delve into -# the objects returned from pyvomi to find serializable facts. The default -# level of 0 is sufficient for most tasks and will be the most performant. -# Beware that the recursion can exceed python's limit (causing traceback), -# cause sluggish script performance and return huge blobs of facts. -# If you do not know what you are doing, leave this set to 1. -#max_object_level=1 - - -# Lower the keynames for facts to make addressing them easier. -#lower_var_keys=True - - -# Don't retrieve and process some VMware attribute keys -# Default values permit to sanitize inventory meta and to improve a little bit -# performance by removing non-common group attributes. -#skip_keys = declaredalarmstate,disabledmethod,dynamicproperty,dynamictype,environmentbrowser,managedby,parent,childtype,resourceconfig - - -# Host alias for objects in the inventory. VMware allows duplicate VM names -# so they can not be considered unique. Use this setting to alter the alias -# returned for the hosts. Any atributes for the guest can be used to build -# this alias. The default combines the config name and the config uuid and -# expects that the ansible_host will be set by the host_pattern. -#alias_pattern={{ config.name + '_' + config.uuid }} - - -# Host pattern is the value set for ansible_host and ansible_ssh_host, which -# needs to be a hostname or ipaddress the ansible controlhost can reach. -#host_pattern={{ guest.ipaddress }} - - -# Host filters are a comma separated list of jinja patterns to remove -# non-matching hosts from the final result. -# EXAMPLES: -# host_filters={{ config.guestid == 'rhel7_64Guest' }} -# host_filters={{ config.cpuhotremoveenabled != False }},{{ runtime.maxmemoryusage >= 512 }} -# host_filters={{ config.cpuhotremoveenabled != False }},{{ runtime.maxmemoryusage >= 512 }} -# host_filters={{ runtime.powerstate == "poweredOn" }} -# host_filters={{ guest.gueststate == "notRunning" }} -# The default value is powerstate of virtual machine equal to "poweredOn". (Changed in version 2.5) -# Runtime state does not require to have vmware tools installed as compared to "guest.gueststate" -#host_filters={{ runtime.powerstate == "poweredOn" }} - - - -# Groupby patterns enable the user to create groups via any possible jinja -# expression. The resulting value will the groupname and the host will be added -# to that group. Be careful to not make expressions that simply return True/False -# because those values will become the literal group name. The patterns can be -# comma delimited to create as many groups as necessary -#groupby_patterns={{ guest.guestid }},{{ 'templates' if config.template else 'guests'}} - -# Group by custom fields will use VMware custom fields to generate hostgroups -# based on {{ custom_field_group_prefix }} + field_name + _ + field_value -# Set groupby_custom_field to True will enable this feature -# If custom field value is comma separated, multiple groups are created. -# Warning: This required max_object_level to be set to 2 or greater. -#groupby_custom_field = False - -# You can customize prefix used by custom field hostgroups generation here. -# vmware_tag_ prefix is the default and consistent with ec2_tag_ -#custom_field_group_prefix = vmware_tag_ - -# You can blacklist custom fields so that they are not included in the -# groupby_custom_field option. This is useful when you have custom fields that -# have values that are unique to individual hosts. Timestamps for example. -# The groupby_custom_field_excludes option should be a comma separated list of custom -# field keys to be blacklisted. -#groupby_custom_field_excludes=,, - -# The script attempts to recurse into virtualmachine objects and serialize -# all available data. The serialization is comprehensive but slow. If the -# vcenter environment is large and the desired properties are known, create -# a 'properties' section in this config and make an arbitrary list of -# key=value settings where the value is a path to a specific property. If -# If this feature is enabled, be sure to fetch every property that is used -# in the jinja expressions defined above. For performance tuning, reduce -# the number of properties to the smallest amount possible and limit the -# use of properties that are not direct attributes of vim.VirtualMachine -#[properties] -#prop01=name -#prop02=config.cpuHotAddEnabled -#prop03=config.cpuHotRemoveEnabled -#prop04=config.instanceUuid -#prop05=config.hardware.numCPU -#prop06=config.template -#prop07=config.name -#prop08=guest.hostName -#prop09=guest.ipAddress -#prop10=guest.guestId -#prop11=guest.guestState -#prop12=runtime.maxMemoryUsage -# In order to populate `customValue` (virtual machine's custom attributes) inside hostvars, -# uncomment following property. Please see - https://github.com/ansible/ansible/issues/41395 -#prop13=customValue diff --git a/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.py b/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.py deleted file mode 100755 index 0271110c965..00000000000 --- a/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.py +++ /dev/null @@ -1,793 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (C): 2017, Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# Requirements -# - pyvmomi >= 6.0.0.2016.4 - -# TODO: -# * more jq examples -# * optional folder hierarchy - -""" -$ jq '._meta.hostvars[].config' data.json | head -{ - "alternateguestname": "", - "instanceuuid": "5035a5cd-b8e8-d717-e133-2d383eb0d675", - "memoryhotaddenabled": false, - "guestfullname": "Red Hat Enterprise Linux 7 (64-bit)", - "changeversion": "2016-05-16T18:43:14.977925Z", - "uuid": "4235fc97-5ddb-7a17-193b-9a3ac97dc7b4", - "cpuhotremoveenabled": false, - "vpmcenabled": false, - "firmware": "bios", -""" - -from __future__ import print_function - -import atexit -import datetime -import itertools -import json -import os -import re -import ssl -import sys -import uuid -from time import time - -from jinja2 import Environment - -from ansible.module_utils.six import integer_types, PY3 -from ansible.module_utils.six.moves import configparser - -try: - import argparse -except ImportError: - sys.exit('Error: This inventory script required "argparse" python module. Please install it or upgrade to python-2.7') - -try: - from pyVmomi import vim, vmodl - from pyVim.connect import SmartConnect, Disconnect -except ImportError: - sys.exit("ERROR: This inventory script required 'pyVmomi' Python module, it was not able to load it") - - -def regex_match(s, pattern): - '''Custom filter for regex matching''' - reg = re.compile(pattern) - if reg.match(s): - return True - else: - return False - - -def select_chain_match(inlist, key, pattern): - '''Get a key from a list of dicts, squash values to a single list, then filter''' - outlist = [x[key] for x in inlist] - outlist = list(itertools.chain(*outlist)) - outlist = [x for x in outlist if regex_match(x, pattern)] - return outlist - - -class VMwareMissingHostException(Exception): - pass - - -class VMWareInventory(object): - __name__ = 'VMWareInventory' - - guest_props = False - instances = [] - debug = False - load_dumpfile = None - write_dumpfile = None - maxlevel = 1 - lowerkeys = True - config = None - cache_max_age = None - cache_path_cache = None - cache_path_index = None - cache_dir = None - server = None - port = None - username = None - password = None - validate_certs = True - host_filters = [] - skip_keys = [] - groupby_patterns = [] - groupby_custom_field_excludes = [] - - safe_types = [bool, str, float, None] + list(integer_types) - iter_types = [dict, list] - - bad_types = ['Array', 'disabledMethod', 'declaredAlarmState'] - - vimTableMaxDepth = { - "vim.HostSystem": 2, - "vim.VirtualMachine": 2, - } - - custom_fields = {} - - # use jinja environments to allow for custom filters - env = Environment() - env.filters['regex_match'] = regex_match - env.filters['select_chain_match'] = select_chain_match - - # translation table for attributes to fetch for known vim types - - vimTable = { - vim.Datastore: ['_moId', 'name'], - vim.ResourcePool: ['_moId', 'name'], - vim.HostSystem: ['_moId', 'name'], - } - - @staticmethod - def _empty_inventory(): - return {"_meta": {"hostvars": {}}} - - def __init__(self, load=True): - self.inventory = VMWareInventory._empty_inventory() - - if load: - # Read settings and parse CLI arguments - self.parse_cli_args() - self.read_settings() - - # Check the cache - cache_valid = self.is_cache_valid() - - # Handle Cache - if self.args.refresh_cache or not cache_valid: - self.do_api_calls_update_cache() - else: - self.debugl('loading inventory from cache') - self.inventory = self.get_inventory_from_cache() - - def debugl(self, text): - if self.args.debug: - try: - text = str(text) - except UnicodeEncodeError: - text = text.encode('utf-8') - print('%s %s' % (datetime.datetime.now(), text)) - - def show(self): - # Data to print - self.debugl('dumping results') - data_to_print = None - if self.args.host: - data_to_print = self.get_host_info(self.args.host) - elif self.args.list: - # Display list of instances for inventory - data_to_print = self.inventory - return json.dumps(data_to_print, indent=2) - - def is_cache_valid(self): - ''' Determines if the cache files have expired, or if it is still valid ''' - - valid = False - - if os.path.isfile(self.cache_path_cache): - mod_time = os.path.getmtime(self.cache_path_cache) - current_time = time() - if (mod_time + self.cache_max_age) > current_time: - valid = True - - return valid - - def do_api_calls_update_cache(self): - ''' Get instances and cache the data ''' - self.inventory = self.instances_to_inventory(self.get_instances()) - self.write_to_cache(self.inventory) - - def write_to_cache(self, data): - ''' Dump inventory to json file ''' - with open(self.cache_path_cache, 'w') as f: - f.write(json.dumps(data, indent=2)) - - def get_inventory_from_cache(self): - ''' Read in jsonified inventory ''' - - jdata = None - with open(self.cache_path_cache, 'r') as f: - jdata = f.read() - return json.loads(jdata) - - def read_settings(self): - ''' Reads the settings from the vmware_inventory.ini file ''' - - scriptbasename = __file__ - scriptbasename = os.path.basename(scriptbasename) - scriptbasename = scriptbasename.replace('.py', '') - - defaults = {'vmware': { - 'server': '', - 'port': 443, - 'username': '', - 'password': '', - 'validate_certs': True, - 'ini_path': os.path.join(os.path.dirname(__file__), '%s.ini' % scriptbasename), - 'cache_name': 'ansible-vmware', - 'cache_path': '~/.ansible/tmp', - 'cache_max_age': 3600, - 'max_object_level': 1, - 'skip_keys': 'declaredalarmstate,' - 'disabledmethod,' - 'dynamicproperty,' - 'dynamictype,' - 'environmentbrowser,' - 'managedby,' - 'parent,' - 'childtype,' - 'resourceconfig', - 'alias_pattern': '{{ config.name + "_" + config.uuid }}', - 'host_pattern': '{{ guest.ipaddress }}', - 'host_filters': '{{ runtime.powerstate == "poweredOn" }}', - 'groupby_patterns': '{{ guest.guestid }},{{ "templates" if config.template else "guests"}}', - 'lower_var_keys': True, - 'custom_field_group_prefix': 'vmware_tag_', - 'groupby_custom_field_excludes': '', - 'groupby_custom_field': False} - } - - if PY3: - config = configparser.ConfigParser() - else: - config = configparser.SafeConfigParser() - - # where is the config? - vmware_ini_path = os.environ.get('VMWARE_INI_PATH', defaults['vmware']['ini_path']) - vmware_ini_path = os.path.expanduser(os.path.expandvars(vmware_ini_path)) - config.read(vmware_ini_path) - - if 'vmware' not in config.sections(): - config.add_section('vmware') - - # apply defaults - for k, v in defaults['vmware'].items(): - if not config.has_option('vmware', k): - config.set('vmware', k, str(v)) - - # where is the cache? - self.cache_dir = os.path.expanduser(config.get('vmware', 'cache_path')) - if self.cache_dir and not os.path.exists(self.cache_dir): - os.makedirs(self.cache_dir) - - # set the cache filename and max age - cache_name = config.get('vmware', 'cache_name') - self.cache_path_cache = self.cache_dir + "/%s.cache" % cache_name - self.debugl('cache path is %s' % self.cache_path_cache) - self.cache_max_age = int(config.getint('vmware', 'cache_max_age')) - - # mark the connection info - self.server = os.environ.get('VMWARE_SERVER', config.get('vmware', 'server')) - self.debugl('server is %s' % self.server) - self.port = int(os.environ.get('VMWARE_PORT', config.get('vmware', 'port'))) - self.username = os.environ.get('VMWARE_USERNAME', config.get('vmware', 'username')) - self.debugl('username is %s' % self.username) - self.password = os.environ.get('VMWARE_PASSWORD', config.get('vmware', 'password', raw=True)) - self.validate_certs = os.environ.get('VMWARE_VALIDATE_CERTS', config.get('vmware', 'validate_certs')) - if self.validate_certs in ['no', 'false', 'False', False]: - self.validate_certs = False - - self.debugl('cert validation is %s' % self.validate_certs) - - # behavior control - self.maxlevel = int(config.get('vmware', 'max_object_level')) - self.debugl('max object level is %s' % self.maxlevel) - self.lowerkeys = config.get('vmware', 'lower_var_keys') - if type(self.lowerkeys) != bool: - if str(self.lowerkeys).lower() in ['yes', 'true', '1']: - self.lowerkeys = True - else: - self.lowerkeys = False - self.debugl('lower keys is %s' % self.lowerkeys) - self.skip_keys = list(config.get('vmware', 'skip_keys').split(',')) - self.debugl('skip keys is %s' % self.skip_keys) - temp_host_filters = list(config.get('vmware', 'host_filters').split('}},')) - for host_filter in temp_host_filters: - host_filter = host_filter.rstrip() - if host_filter != "": - if not host_filter.endswith("}}"): - host_filter += "}}" - self.host_filters.append(host_filter) - self.debugl('host filters are %s' % self.host_filters) - - temp_groupby_patterns = list(config.get('vmware', 'groupby_patterns').split('}},')) - for groupby_pattern in temp_groupby_patterns: - groupby_pattern = groupby_pattern.rstrip() - if groupby_pattern != "": - if not groupby_pattern.endswith("}}"): - groupby_pattern += "}}" - self.groupby_patterns.append(groupby_pattern) - self.debugl('groupby patterns are %s' % self.groupby_patterns) - temp_groupby_custom_field_excludes = config.get('vmware', 'groupby_custom_field_excludes') - self.groupby_custom_field_excludes = [x.strip('"') for x in [y.strip("'") for y in temp_groupby_custom_field_excludes.split(",")]] - self.debugl('groupby exclude strings are %s' % self.groupby_custom_field_excludes) - - # Special feature to disable the brute force serialization of the - # virtual machine objects. The key name for these properties does not - # matter because the values are just items for a larger list. - if config.has_section('properties'): - self.guest_props = [] - for prop in config.items('properties'): - self.guest_props.append(prop[1]) - - # save the config - self.config = config - - def parse_cli_args(self): - ''' Command line argument processing ''' - - parser = argparse.ArgumentParser(description='Produce an Ansible Inventory file based on PyVmomi') - parser.add_argument('--debug', action='store_true', default=False, - help='show debug info') - parser.add_argument('--list', action='store_true', default=True, - help='List instances (default: True)') - parser.add_argument('--host', action='store', - help='Get all the variables about a specific instance') - parser.add_argument('--refresh-cache', action='store_true', default=False, - help='Force refresh of cache by making API requests to VSphere (default: False - use cache files)') - parser.add_argument('--max-instances', default=None, type=int, - help='maximum number of instances to retrieve') - self.args = parser.parse_args() - - def get_instances(self): - ''' Get a list of vm instances with pyvmomi ''' - kwargs = {'host': self.server, - 'user': self.username, - 'pwd': self.password, - 'port': int(self.port)} - - if self.validate_certs and hasattr(ssl, 'SSLContext'): - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.verify_mode = ssl.CERT_REQUIRED - context.check_hostname = True - kwargs['sslContext'] = context - elif self.validate_certs and not hasattr(ssl, 'SSLContext'): - sys.exit('pyVim does not support changing verification mode with python < 2.7.9. Either update ' - 'python or use validate_certs=false.') - elif not self.validate_certs and hasattr(ssl, 'SSLContext'): - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.verify_mode = ssl.CERT_NONE - context.check_hostname = False - kwargs['sslContext'] = context - elif not self.validate_certs and not hasattr(ssl, 'SSLContext'): - # Python 2.7.9 < or RHEL/CentOS 7.4 < - pass - - return self._get_instances(kwargs) - - def _get_instances(self, inkwargs): - ''' Make API calls ''' - instances = [] - si = None - try: - si = SmartConnect(**inkwargs) - except ssl.SSLError as connection_error: - if '[SSL: CERTIFICATE_VERIFY_FAILED]' in str(connection_error) and self.validate_certs: - sys.exit("Unable to connect to ESXi server due to %s, " - "please specify validate_certs=False and try again" % connection_error) - - except Exception as exc: - self.debugl("Unable to connect to ESXi server due to %s" % exc) - sys.exit("Unable to connect to ESXi server due to %s" % exc) - - self.debugl('retrieving all instances') - if not si: - sys.exit("Could not connect to the specified host using specified " - "username and password") - atexit.register(Disconnect, si) - content = si.RetrieveContent() - - # Create a search container for virtualmachines - self.debugl('creating containerview for virtualmachines') - container = content.rootFolder - viewType = [vim.VirtualMachine] - recursive = True - containerView = content.viewManager.CreateContainerView(container, viewType, recursive) - children = containerView.view - for child in children: - # If requested, limit the total number of instances - if self.args.max_instances: - if len(instances) >= self.args.max_instances: - break - instances.append(child) - self.debugl("%s total instances in container view" % len(instances)) - - if self.args.host: - instances = [x for x in instances if x.name == self.args.host] - - instance_tuples = [] - for instance in instances: - if self.guest_props: - ifacts = self.facts_from_proplist(instance) - else: - ifacts = self.facts_from_vobj(instance) - instance_tuples.append((instance, ifacts)) - self.debugl('facts collected for all instances') - - try: - cfm = content.customFieldsManager - if cfm is not None and cfm.field: - for f in cfm.field: - if not f.managedObjectType or f.managedObjectType == vim.VirtualMachine: - self.custom_fields[f.key] = f.name - self.debugl('%d custom fields collected' % len(self.custom_fields)) - except vmodl.RuntimeFault as exc: - self.debugl("Unable to gather custom fields due to %s" % exc.msg) - except IndexError as exc: - self.debugl("Unable to gather custom fields due to %s" % exc) - - return instance_tuples - - def instances_to_inventory(self, instances): - ''' Convert a list of vm objects into a json compliant inventory ''' - self.debugl('re-indexing instances based on ini settings') - inventory = VMWareInventory._empty_inventory() - inventory['all'] = {} - inventory['all']['hosts'] = [] - for idx, instance in enumerate(instances): - # make a unique id for this object to avoid vmware's - # numerous uuid's which aren't all unique. - thisid = str(uuid.uuid4()) - idata = instance[1] - - # Put it in the inventory - inventory['all']['hosts'].append(thisid) - inventory['_meta']['hostvars'][thisid] = idata.copy() - inventory['_meta']['hostvars'][thisid]['ansible_uuid'] = thisid - - # Make a map of the uuid to the alias the user wants - name_mapping = self.create_template_mapping( - inventory, - self.config.get('vmware', 'alias_pattern') - ) - - # Make a map of the uuid to the ssh hostname the user wants - host_mapping = self.create_template_mapping( - inventory, - self.config.get('vmware', 'host_pattern') - ) - - # Reset the inventory keys - for k, v in name_mapping.items(): - - if not host_mapping or k not in host_mapping: - continue - - # set ansible_host (2.x) - try: - inventory['_meta']['hostvars'][k]['ansible_host'] = host_mapping[k] - # 1.9.x backwards compliance - inventory['_meta']['hostvars'][k]['ansible_ssh_host'] = host_mapping[k] - except Exception: - continue - - if k == v: - continue - - # add new key - inventory['all']['hosts'].append(v) - inventory['_meta']['hostvars'][v] = inventory['_meta']['hostvars'][k] - - # cleanup old key - inventory['all']['hosts'].remove(k) - inventory['_meta']['hostvars'].pop(k, None) - - self.debugl('pre-filtered hosts:') - for i in inventory['all']['hosts']: - self.debugl(' * %s' % i) - # Apply host filters - for hf in self.host_filters: - if not hf: - continue - self.debugl('filter: %s' % hf) - filter_map = self.create_template_mapping(inventory, hf, dtype='boolean') - for k, v in filter_map.items(): - if not v: - # delete this host - inventory['all']['hosts'].remove(k) - inventory['_meta']['hostvars'].pop(k, None) - - self.debugl('post-filter hosts:') - for i in inventory['all']['hosts']: - self.debugl(' * %s' % i) - - # Create groups - for gbp in self.groupby_patterns: - groupby_map = self.create_template_mapping(inventory, gbp) - for k, v in groupby_map.items(): - if v not in inventory: - inventory[v] = {} - inventory[v]['hosts'] = [] - if k not in inventory[v]['hosts']: - inventory[v]['hosts'].append(k) - - if self.config.get('vmware', 'groupby_custom_field'): - for k, v in inventory['_meta']['hostvars'].items(): - if 'customvalue' in v: - for tv in v['customvalue']: - newkey = None - field_name = self.custom_fields[tv['key']] if tv['key'] in self.custom_fields else tv['key'] - if field_name in self.groupby_custom_field_excludes: - continue - values = [] - keylist = map(lambda x: x.strip(), tv['value'].split(',')) - for kl in keylist: - try: - newkey = "%s%s_%s" % (self.config.get('vmware', 'custom_field_group_prefix'), str(field_name), kl) - newkey = newkey.strip() - except Exception as e: - self.debugl(e) - values.append(newkey) - for tag in values: - if not tag: - continue - if tag not in inventory: - inventory[tag] = {} - inventory[tag]['hosts'] = [] - if k not in inventory[tag]['hosts']: - inventory[tag]['hosts'].append(k) - - return inventory - - def create_template_mapping(self, inventory, pattern, dtype='string'): - ''' Return a hash of uuid to templated string from pattern ''' - mapping = {} - for k, v in inventory['_meta']['hostvars'].items(): - t = self.env.from_string(pattern) - newkey = None - try: - newkey = t.render(v) - newkey = newkey.strip() - except Exception as e: - self.debugl(e) - if not newkey: - continue - elif dtype == 'integer': - newkey = int(newkey) - elif dtype == 'boolean': - if newkey.lower() == 'false': - newkey = False - elif newkey.lower() == 'true': - newkey = True - elif dtype == 'string': - pass - mapping[k] = newkey - return mapping - - def facts_from_proplist(self, vm): - '''Get specific properties instead of serializing everything''' - - rdata = {} - for prop in self.guest_props: - self.debugl('getting %s property for %s' % (prop, vm.name)) - key = prop - if self.lowerkeys: - key = key.lower() - - if '.' not in prop: - # props without periods are direct attributes of the parent - vm_property = getattr(vm, prop) - if isinstance(vm_property, vim.CustomFieldsManager.Value.Array): - temp_vm_property = [] - for vm_prop in vm_property: - temp_vm_property.append({'key': vm_prop.key, - 'value': vm_prop.value}) - rdata[key] = temp_vm_property - else: - rdata[key] = vm_property - else: - # props with periods are subkeys of parent attributes - parts = prop.split('.') - total = len(parts) - 1 - - # pointer to the current object - val = None - # pointer to the current result key - lastref = rdata - - for idx, x in enumerate(parts): - - if isinstance(val, dict): - if x in val: - val = val.get(x) - elif x.lower() in val: - val = val.get(x.lower()) - else: - # if the val wasn't set yet, get it from the parent - if not val: - try: - val = getattr(vm, x) - except AttributeError as e: - self.debugl(e) - else: - # in a subkey, get the subprop from the previous attrib - try: - val = getattr(val, x) - except AttributeError as e: - self.debugl(e) - - # make sure it serializes - val = self._process_object_types(val) - - # lowercase keys if requested - if self.lowerkeys: - x = x.lower() - - # change the pointer or set the final value - if idx != total: - if x not in lastref: - lastref[x] = {} - lastref = lastref[x] - else: - lastref[x] = val - if self.args.debug: - self.debugl("For %s" % vm.name) - for key in list(rdata.keys()): - if isinstance(rdata[key], dict): - for ikey in list(rdata[key].keys()): - self.debugl("Property '%s.%s' has value '%s'" % (key, ikey, rdata[key][ikey])) - else: - self.debugl("Property '%s' has value '%s'" % (key, rdata[key])) - return rdata - - def facts_from_vobj(self, vobj, level=0): - ''' Traverse a VM object and return a json compliant data structure ''' - - # pyvmomi objects are not yet serializable, but may be one day ... - # https://github.com/vmware/pyvmomi/issues/21 - - # WARNING: - # Accessing an object attribute will trigger a SOAP call to the remote. - # Increasing the attributes collected or the depth of recursion greatly - # increases runtime duration and potentially memory+network utilization. - - if level == 0: - try: - self.debugl("get facts for %s" % vobj.name) - except Exception as e: - self.debugl(e) - - rdata = {} - - methods = dir(vobj) - methods = [str(x) for x in methods if not x.startswith('_')] - methods = [x for x in methods if x not in self.bad_types] - methods = [x for x in methods if not x.lower() in self.skip_keys] - methods = sorted(methods) - - for method in methods: - # Attempt to get the method, skip on fail - try: - methodToCall = getattr(vobj, method) - except Exception as e: - continue - - # Skip callable methods - if callable(methodToCall): - continue - - if self.lowerkeys: - method = method.lower() - - rdata[method] = self._process_object_types( - methodToCall, - thisvm=vobj, - inkey=method, - ) - - return rdata - - def _process_object_types(self, vobj, thisvm=None, inkey='', level=0): - ''' Serialize an object ''' - rdata = {} - - if type(vobj).__name__ in self.vimTableMaxDepth and level >= self.vimTableMaxDepth[type(vobj).__name__]: - return rdata - - if vobj is None: - rdata = None - elif type(vobj) in self.vimTable: - rdata = {} - for key in self.vimTable[type(vobj)]: - try: - rdata[key] = getattr(vobj, key) - except Exception as e: - self.debugl(e) - - elif issubclass(type(vobj), str) or isinstance(vobj, str): - if vobj.isalnum(): - rdata = vobj - else: - rdata = vobj.encode('utf-8').decode('utf-8') - elif issubclass(type(vobj), bool) or isinstance(vobj, bool): - rdata = vobj - elif issubclass(type(vobj), integer_types) or isinstance(vobj, integer_types): - rdata = vobj - elif issubclass(type(vobj), float) or isinstance(vobj, float): - rdata = vobj - elif issubclass(type(vobj), list) or issubclass(type(vobj), tuple): - rdata = [] - try: - vobj = sorted(vobj) - except Exception: - pass - - for idv, vii in enumerate(vobj): - if level + 1 <= self.maxlevel: - vid = self._process_object_types( - vii, - thisvm=thisvm, - inkey=inkey + '[' + str(idv) + ']', - level=(level + 1) - ) - - if vid: - rdata.append(vid) - - elif issubclass(type(vobj), dict): - pass - - elif issubclass(type(vobj), object): - methods = dir(vobj) - methods = [str(x) for x in methods if not x.startswith('_')] - methods = [x for x in methods if x not in self.bad_types] - methods = [x for x in methods if not inkey + '.' + x.lower() in self.skip_keys] - methods = sorted(methods) - - for method in methods: - # Attempt to get the method, skip on fail - try: - methodToCall = getattr(vobj, method) - except Exception as e: - continue - - if callable(methodToCall): - continue - - if self.lowerkeys: - method = method.lower() - if level + 1 <= self.maxlevel: - try: - rdata[method] = self._process_object_types( - methodToCall, - thisvm=thisvm, - inkey=inkey + '.' + method, - level=(level + 1) - ) - except vim.fault.NoPermission: - self.debugl("Skipping method %s (NoPermission)" % method) - else: - pass - - return rdata - - def get_host_info(self, host): - ''' Return hostvars for a single host ''' - - if host in self.inventory['_meta']['hostvars']: - return self.inventory['_meta']['hostvars'][host] - elif self.args.host and self.inventory['_meta']['hostvars']: - match = None - for k, v in self.inventory['_meta']['hostvars'].items(): - if self.inventory['_meta']['hostvars'][k]['name'] == self.args.host: - match = k - break - if match: - return self.inventory['_meta']['hostvars'][match] - else: - raise VMwareMissingHostException('%s not found' % host) - else: - raise VMwareMissingHostException('%s not found' % host) - - -if __name__ == "__main__": - # Run the script - print(VMWareInventory().show()) diff --git a/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.sh b/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.sh deleted file mode 100755 index b6399f14fbf..00000000000 --- a/test/integration/targets/incidental_script_inventory_vmware_inventory/vmware_inventory.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -python.py "./vmware_inventory.py" "$@" diff --git a/test/integration/targets/incidental_vmware_guest/aliases b/test/integration/targets/incidental_vmware_guest/aliases deleted file mode 100644 index d9ee32bcc63..00000000000 --- a/test/integration/targets/incidental_vmware_guest/aliases +++ /dev/null @@ -1,3 +0,0 @@ -shippable/vcenter/incidental -cloud/vcenter -needs/target/incidental_vmware_prepare_tests diff --git a/test/integration/targets/incidental_vmware_guest/defaults/main.yml b/test/integration/targets/incidental_vmware_guest/defaults/main.yml deleted file mode 100644 index dfb0fd65dc5..00000000000 --- a/test/integration/targets/incidental_vmware_guest/defaults/main.yml +++ /dev/null @@ -1,33 +0,0 @@ -vmware_guest_test_playbooks: - - boot_firmware_d1_c1_f0.yml - - boot_firmware_d1_c1_f0.yml - - cdrom_d1_c1_f0.yml - - check_mode.yml - - clone_customize_guest_test.yml - - clone_d1_c1_f0.yml - - clone_resize_disks.yml - - clone_with_convert.yml - - create_d1_c1_f0.yml - - create_guest_invalid_d1_c1_f0.yml - - create_nw_d1_c1_f0.yml - - create_rp_d1_c1_f0.yml - - delete_vm.yml - - disk_mode_d1_c1_f0.yml - - disk_size_d1_c1_f0.yml - - disk_type_d1_c1_f0.yml - - linked_clone_d1_c1_f0.yml - - mac_address_d1_c1_f0.yml - - max_connections.yml - - mem_reservation.yml - - network_negative_test.yml - - network_with_device.yml -# Currently, VCSIM doesn't support DVPG (as portkeys are not available) so commenting this test -# - network_with_dvpg.yml -# - network_with_portgroup.yml - - non_existent_vm_ops.yml - - poweroff_d1_c1_f0.yml - - poweroff_d1_c1_f1.yml -# - template_d1_c1_f0.yml - - vapp_d1_c1_f0.yml - - reconfig_vm_to_latest_version.yml - - remove_vm_from_inventory.yml diff --git a/test/integration/targets/incidental_vmware_guest/tasks/boot_firmware_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/boot_firmware_d1_c1_f0.yml deleted file mode 100644 index aade1494e3f..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/boot_firmware_d1_c1_f0.yml +++ /dev/null @@ -1,117 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs with boot_firmware as 'bios' - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - boot_firmware: "bios" - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: "{{ f0 }}" - register: clone_d1_c1_f0 - -- debug: var=clone_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_d1_c1_f0 is changed - -# VCSIM does not recognizes existing VMs boot firmware -- when: vcsim is not defined - block: - - name: create new VMs again with boot_firmware as 'bios' - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm2 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - boot_firmware: "bios" - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: "{{ f0 }}" - register: clone_d1_c1_f0 - - debug: var=clone_d1_c1_f0 - - name: assert that changes were not made - assert: - that: - - clone_d1_c1_f0 is changed - -- name: create new VMs with boot_firmware as 'efi' - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm3 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - boot_firmware: "efi" - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: "{{ f0 }}" - register: clone_d1_c1_f0 - -- debug: var=clone_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_d1_c1_f0 is changed - -# VCSIM does not recognizes existing VMs boot firmware -- when: vcsim is not defined - block: - - name: create new VMs again with boot_firmware as 'efi' - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm3 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - boot_firmware: "efi" - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: "{{ f0 }}" - register: clone_d1_c1_f0 - - debug: var=clone_d1_c1_f0 - - name: assert that changes were not made - assert: - that: - - not (clone_d1_c1_f0 is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/cdrom_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/cdrom_d1_c1_f0.yml deleted file mode 100644 index 467cf25d1a3..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/cdrom_d1_c1_f0.yml +++ /dev/null @@ -1,269 +0,0 @@ -- name: Create VM with CDROM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: vm - name: test_vm1 - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: centos64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] centos.iso" - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was created - assert: - that: - - "cdrom_vm.changed == true" - -- name: Update CDROM to iso for the new VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "vm" - name: test_vm1 - datastore: "{{ rw_datastore }}" - datacenter: "{{ dc1 }}" - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] fedora.iso" - state: present - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was changed - assert: - that: - - "cdrom_vm.changed == true" - -- name: Update CDROM to client for the new VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: vm - name: test_vm1 - datacenter: "{{ dc1 }}" - cdrom: - type: client - state: present - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was changed - assert: - that: - - "cdrom_vm.changed == true" - -- name: clone vm - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm2 - template: test_vm1 - datacenter: "{{ dc1 }}" - state: poweredoff - folder: vm - convert: thin - -- name: Update CDROM to none for the new VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: vm - name: test_vm2 - datacenter: "{{ dc1 }}" - cdrom: - type: none - state: present - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was changed - assert: - that: - - "cdrom_vm.changed == true" - -- name: Create VM with multiple disks and a CDROM - GitHub issue 38679 - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "{{ f0 }}" - name: test_vm3 - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: centos64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] fedora.iso" - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was created - assert: - that: - - "cdrom_vm.changed == true" - -- name: Create VM with multiple CDROMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: vm - name: test_vm1 - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: centos64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - cdrom: - - controller_type: ide - controller_number: 0 - unit_number: 0 - type: iso - iso_path: "[{{ ro_datastore }}] centos.iso" - - controller_type: ide - controller_number: 0 - unit_number: 1 - type: client - - controller_number: 1 - unit_number: 0 - type: none - - controller_number: 1 - unit_number: 1 - type: client - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was created - assert: - that: - - "cdrom_vm.changed == true" - -- name: Remove the last 2 CDROMs and update the first 2 for the new VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: vm - name: test_vm1 - datacenter: "{{ dc1 }}" - cdrom: - - controller_type: ide - controller_number: 0 - unit_number: 0 - type: client - - controller_type: ide - controller_number: 0 - unit_number: 1 - type: iso - iso_path: "[{{ ro_datastore }}] fedora.iso" - - controller_type: ide - controller_number: 1 - unit_number: 0 - state: absent - - controller_type: ide - controller_number: 1 - unit_number: 1 - state: absent - state: present - register: cdrom_vm - -- debug: var=cdrom_vm - -- name: assert the VM was changed - assert: - that: - - "cdrom_vm.changed == true" - -# VCSIM fails with invalidspec exception but real vCenter PASS testcase -# Commenting this testcase till the time -- when: vcsim is not defined - block: - - name: Again create VM with multiple disks and a CDROM - GitHub issue 38679 - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "{{ f0 }}" - name: test_vm3 - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: centos64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] base.iso" - register: cdrom_vm - - debug: var=cdrom_vm - - name: assert the VM was created - assert: - that: - - cdrom_vm is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/check_mode.yml b/test/integration/targets/incidental_vmware_guest/tasks/check_mode.yml deleted file mode 100644 index d3f6f226349..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/check_mode.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: Perform all operation in check mode - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ virtual_machines[0].name }}" - datacenter: "{{ dc1 }}" - state: "{{ item }}" - with_items: - - absent - - present - - poweredoff - - poweredon - - restarted - - suspended - - shutdownguest - - rebootguest - register: check_mode_state - check_mode: yes - -- debug: - var: check_mode_state - -- name: assert that changes were made - assert: - that: - - "check_mode_state.results|map(attribute='changed')|unique|list == [true]" - - "check_mode_state.results|map(attribute='vm_name')|unique|list == [ virtual_machines[0].name ]" - -- name: Perform all operation on non-existent VM in check mode - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: non_existent_vm - datacenter: "{{ dc1 }}" - state: "{{ item }}" - with_items: - - present - - poweredoff - - poweredon - - restarted - - suspended - register: check_mode_state - check_mode: yes - -- debug: - var: check_mode_state - -- name: assert that changes were made - assert: - that: - - "check_mode_state.results|map(attribute='changed')|unique|list == [true]" - - "check_mode_state.results|map(attribute='desired_operation')|unique|list == ['deploy_vm']" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/clone_customize_guest_test.yml b/test/integration/targets/incidental_vmware_guest/tasks/clone_customize_guest_test.yml deleted file mode 100644 index f40848298c3..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/clone_customize_guest_test.yml +++ /dev/null @@ -1,47 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2019, Pavan Bidkar -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: clone vm from template and customize GOS - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - template: "{{ virtual_machines[0].name }}" - datacenter: "{{ dc1 }}" - state: poweredoff - folder: "{{ virtual_machines[0].folder }}" - convert: thin - register: clone_customize - -- debug: - var: clone_customize - -- name: assert that changes were made - assert: - that: - - clone_customize is changed - -- name: clone vm from template and customize GOS again - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - template: "{{ virtual_machines[0].name }}" - datacenter: "{{ dc1 }}" - state: poweredoff - folder: "{{ virtual_machines[0].folder }}" - convert: thin - register: clone_customize_again - -- debug: - var: clone_customize_again - -- name: assert that changes were not made - assert: - that: - - not (clone_customize_again is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/clone_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/clone_d1_c1_f0.yml deleted file mode 100644 index 3b3d2ad543f..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/clone_d1_c1_f0.yml +++ /dev/null @@ -1,101 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, James Tanner -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new linked clone without specifying snapshot_src - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - template: "{{ virtual_machines[0].name }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - linked_clone: True - register: linked_clone_d1_c1_f0 - ignore_errors: True - -- debug: - var: linked_clone_d1_c1_f0 - -- name: assert that changes were not made - assert: - that: - - not (linked_clone_d1_c1_f0 is changed) - -- name: create new linked clone without specifying linked_clone - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm2 - template: "{{ virtual_machines[0].name }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - snapshot_src: "snap_shot1" - register: linked_clone_d1_c1_f0 - ignore_errors: True - -- debug: - var: linked_clone_d1_c1_f0 - -- name: assert that changes were not made - assert: - that: - - not (linked_clone_d1_c1_f0 is changed) - -# TODO: VCSIM: snapshot is not supported in current vcsim -# -#- name: create new linked clone with linked_clone and snapshot_src -# vmware_guest: -# validate_certs: False -# hostname: "{{ vcenter_hostname }}" -# username: "{{ vcenter_username }}" -# password: "{{ vcenter_password }}" -# name: "{{ 'new_vm_' + item|basename }}" -# template: "{{ item|basename }}" -# guest_id: centos64Guest -# datacenter: "{{ (item|basename).split('_')[0] }}" -# folder: "{{ item|dirname }}" -# snapshot_src: "snap_shot1" -# linked_clone: True -# with_items: "{{ vmlist['json'] }}" -# register: linked_clone_d1_c1_f0 -# ignore_errors: True - -#- debug: var=linked_clone_d1_c1_f0 - -#- name: assert that changes were made -# assert: -# that: -# - "linked_clone_d1_c1_f0.results|map(attribute='changed')|unique|list == [true]" - -# TODO: VCSIM: snapshot is not supported in current vcsim -# -#- name: create new linked clone with linked_clone and snapshot_src again -# vmware_guest: -# validate_certs: False -# hostname: "{{ vcenter_hostname }}" -# username: "{{ vcenter_username }}" -# password: "{{ vcenter_password }}" -# name: "{{ 'new_vm_' + item|basename }}" -# template: "{{ item|basename }}" -# guest_id: centos64Guest -# datacenter: "{{ (item|basename).split('_')[0] }}" -# folder: "{{ item|dirname }}" -# snapshot_src: "snap_shot1" -# linked_clone: True -# with_items: "{{ vmlist['json'] }}" -# register: linked_clone_d1_c1_f0 -# ignore_errors: True - -#- debug: var=linked_clone_d1_c1_f0 - -#- name: assert that changes were not made -# assert: -# that: -# - "linked_clone_d1_c1_f0.results|map(attribute='changed')|unique|list == [false]" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/clone_resize_disks.yml b/test/integration/targets/incidental_vmware_guest/tasks/clone_resize_disks.yml deleted file mode 100644 index 70004d161b3..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/clone_resize_disks.yml +++ /dev/null @@ -1,77 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2019, Noe Gonzalez -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- when: vcsim is not defined - block: - - name: create new VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: clone_resize_disks_original - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - folder: "{{ f0 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - guest_id: centos7_64Guest - disk: - - size_gb: 1 - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - - - name: convert to VM template - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: clone_resize_disks_original - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - folder: "{{ f0 }}" - is_template: True - - - name: clone template and modify disks - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: clone_resize_disks_clone - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - folder: "{{ f0 }}" - disk: - - size_gb: 2 - type: thin - datastore: "{{ rw_datastore }}" - - size_gb: 3 - type: thin - datastore: "{{ rw_datastore }}" - template: clone_resize_disks_original - state: poweredoff - register: l_clone_template_modify_disks - - - assert: - that: - - l_clone_template_modify_disks.changed | bool - - - name: delete VM clone & original template - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ item }}" - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - folder: "{{ f0 }}" - state: absent - with_items: - - clone_resize_disks_original - - clone_resize_disks_clone diff --git a/test/integration/targets/incidental_vmware_guest/tasks/clone_with_convert.yml b/test/integration/targets/incidental_vmware_guest/tasks/clone_with_convert.yml deleted file mode 100644 index bf3abfae36d..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/clone_with_convert.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Christophe FERREIRA -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: clone vm from template and convert to thin - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - template: "{{ virtual_machines[0].name }}" - datacenter: "{{ dc1 }}" - state: poweredoff - folder: "{{ virtual_machines[0].folder }}" - convert: thin - register: clone_thin - -- debug: var=clone_thin - -- name: assert that changes were made - assert: - that: - - clone_thin is changed - -- name: clone vm from template and convert to thick - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm2 - template: "{{ virtual_machines[0].name }}" - datacenter: "{{ dc1 }}" - state: poweredoff - folder: "{{ virtual_machines[0].folder }}" - convert: thick - register: clone_thick - -- debug: var=clone_thick - -- name: assert that changes were made - assert: - that: - - clone_thick is changed - -- name: clone vm from template and convert to eagerzeroedthick - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm3 - template: "{{ virtual_machines[0].name }}" - datacenter: "{{ dc1 }}" - state: poweredoff - folder: "{{ virtual_machines[0].folder }}" - convert: eagerzeroedthick - register: clone_eagerzeroedthick - -- debug: var=clone_eagerzeroedthick - -- name: assert that changes were made - assert: - that: - - clone_eagerzeroedthick is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/create_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/create_d1_c1_f0.yml deleted file mode 100644 index b4ee85002d5..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/create_d1_c1_f0.yml +++ /dev/null @@ -1,164 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, James Tanner -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - num_cpu_cores_per_socket: 1 - memory_mb: 128 - hotadd_memory: true - hotadd_cpu: false - # vcsim does not support these settings, so commenting - # till the time. - # memory_reservation: 128 - # memory_reservation_lock: False - # nested_virt: True - # hotremove_cpu: True - # mem_limit: 8096 - # mem_reservation: 4096 - # cpu_limit: 8096 - # cpu_reservation: 4096 - max_connections: 10 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: '{{ f0 }}' - register: clone_d1_c1_f0 - -- debug: var=clone_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_d1_c1_f0 is changed - -- name: create the VM again - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - num_cpu_cores_per_socket: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: '{{ f0 }}' - register: clone_d1_c1_f0_recreate - -- debug: var=clone_d1_c1_f0_recreate - -- name: assert that no changes were made after re-creating - assert: - that: - - not (clone_d1_c1_f0_recreate is changed) - -- name: modify the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 2 - memory_mb: 128 - state: present - folder: '{{ f0 }}' - register: clone_d1_c1_f0_modify - -- debug: var=clone_d1_c1_f0_modify - -- name: assert that changes were made with modification - assert: - that: - - clone_d1_c1_f0_modify is changed - -- name: re-modify the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 2 - memory_mb: 128 - state: present - folder: '{{ f0 }}' - register: clone_d1_c1_f0_remodify - -- debug: var=clone_d1_c1_f0_remodify - -- name: assert that no changes were made when re-modified - assert: - that: - - not (clone_d1_c1_f0_remodify is changed) - -- name: delete the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - #guest_id: centos64Guest - datacenter: "{{ dc1 }}" - state: absent - folder: '{{ f0 }}' - register: clone_d1_c1_f0_delete - -- debug: var=clone_d1_c1_f0_delete - -- name: assert that changes were made with deletion - assert: - that: - - clone_d1_c1_f0_delete is changed - -- name: re-delete the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - #guest_id: centos64Guest - datacenter: "{{ dc1 }}" - state: absent - folder: '{{ f0 }}' - register: clone_d1_c1_f0_redelete - -- debug: var=clone_d1_c1_f0_redelete - -- name: assert that no changes were made with redeletion - assert: - that: - - not (clone_d1_c1_f0_redelete is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/create_guest_invalid_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/create_guest_invalid_d1_c1_f0.yml deleted file mode 100644 index 8a0b6468b65..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/create_guest_invalid_d1_c1_f0.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- when: vcsim is not defined - block: - - name: create new virtual machine with invalid guest id - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: invalid_vm - guest_id: "invalid_guest_id" - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: present - folder: "{{ f0 }}" - register: invalid_guest_0001_d1_c1_f0 - ignore_errors: yes - - debug: var=invalid_guest_0001_d1_c1_f0 - - name: assert that changes were made - assert: - that: - - "not (invalid_guest_0001_d1_c1_f0 is changed)" - - "'configSpec.guestId' in invalid_guest_0001_d1_c1_f0['msg']" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/create_nw_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/create_nw_d1_c1_f0.yml deleted file mode 100644 index 2a22dce2f61..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/create_nw_d1_c1_f0.yml +++ /dev/null @@ -1,38 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: 'VM Network' - device_type: vmxnet3 - ip: 192.168.10.1 - netmask: 255.255.255.0 - wake_on_lan: True - start_connected: True - allow_guest_control: True - state: poweredoff - folder: F0 - register: clone_d1_c1_f0 - -- debug: var=clone_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_d1_c1_f0 is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/create_rp_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/create_rp_d1_c1_f0.yml deleted file mode 100644 index 30319b78d7e..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/create_rp_d1_c1_f0.yml +++ /dev/null @@ -1,205 +0,0 @@ -# Create one with the defaults -- name: create new VM with default resource pool - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: F0 - register: clone_rp_d1_c1_f0 - -- debug: var=clone_rp_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_rp_d1_c1_f0 is changed - -- name: delete the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - #guest_id: centos64Guest - datacenter: "{{ dc1 }}" - state: absent - folder: F0 - register: clone_rp_d1_c1_f0_delete - -- debug: var=clone_rp_d1_c1_f0_delete - -- name: assert that changes were made with deletion - assert: - that: - - clone_rp_d1_c1_f0_delete is changed - -# now create with just a cluster -- name: create new VM with default resource pool in cluster - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: F0 - register: clone_rpc_d1_c1_f0 - -- debug: var=clone_rpc_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_rpc_d1_c1_f0 is changed - -- name: delete the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - #guest_id: centos64Guest - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - state: absent - folder: F0 - register: clone_rpc_d1_c1_f0_delete - -- debug: var=clone_rpc_d1_c1_f0_delete - -- name: assert that changes were made with deletion - assert: - that: - - clone_rpc_d1_c1_f0_delete is changed - -# now create with a specific resource pool -- name: create new VM with specific resource pool in cluster - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: DC0_C0_RP1 - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: F0 - register: clone_rpcp_d1_c1_f0 - -- debug: var=clone_rpcp_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_rpcp_d1_c1_f0 is changed - -- name: delete the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - #guest_id: centos64Guest - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - state: absent - folder: F0 - register: clone_rpcp_d1_c1_f0_delete - -- debug: var=clone_rpcp_d1_c1_f0_delete - -- name: assert that changes were made with deletion - assert: - that: - - clone_rpcp_d1_c1_f0_delete is changed - -# now create with a specific host -- name: create new VM with specific host - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - esxi_hostname: '{{ esxi1 }}' - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: F0 - register: clone_rph_d1_c1_f0 - -- debug: var=clone_rph_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - clone_rph_d1_c1_f0 is changed - -- name: delete the new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - #template: "{{ item|basename }}" - #guest_id: centos64Guest - datacenter: "{{ dc1 }}" - state: absent - folder: F0 - register: clone_rph_d1_c1_f0_delete - -- debug: var=clone_rph_d1_c1_f0_delete - -- name: assert that changes were made with deletion - assert: - that: - - clone_rph_d1_c1_f0_delete is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/delete_vm.yml b/test/integration/targets/incidental_vmware_guest/tasks/delete_vm.yml deleted file mode 100644 index 600df0fc50e..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/delete_vm.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: Delete VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: nothinghere - datacenter: "{{ dc1 }}" - state: absent - register: delete_vm - ignore_errors: yes - -- debug: var=delete_vm - -- name: assert that changes were made - assert: - that: - - "not delete_vm.changed" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/disk_mode_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/disk_mode_d1_c1_f0.yml deleted file mode 100644 index 7a14d11981a..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/disk_mode_d1_c1_f0.yml +++ /dev/null @@ -1,89 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs with invalid disk mode - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: eagerzeroedthick - datastore: "{{ rw_datastore }}" - disk_mode: 'invalid_disk_mode' - state: poweredoff - folder: "{{ f0 }}" - register: test_vm1 - ignore_errors: True - -- debug: var=test_vm1 - -- name: assert that changes were not made - assert: - that: - - not(test_vm1 is changed) - -- name: create new VMs with valid disk mode - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: eagerzeroedthick - datastore: "{{ rw_datastore }}" - disk_mode: 'independent_persistent' - state: poweredoff - folder: "{{ f0 }}" - register: test_vm1_2 - -- debug: var=test_vm1_2 - -- name: assert that changes were made - assert: - that: - - test_vm1_2 is changed - -#TODO: vcsim does not support reconfiguration of disk mode, fails with types.InvalidDeviceSpec -- when: vcsim is not defined - block: - - name: create new VMs with valid disk mode again - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: eagerzeroedthick - datastore: "{{ rw_datastore }}" - disk_mode: 'independent_persistent' - state: poweredoff - folder: "{{ f0 }}" - register: test_vm1_2 - - debug: var=test_vm1_2 - - name: assert that changes were not made - assert: - that: - - not (test_vm1_2 is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/disk_size_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/disk_size_d1_c1_f0.yml deleted file mode 100644 index c40f19e6240..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/disk_size_d1_c1_f0.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs with invalid disk size - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 0gb - type: eagerzeroedthick - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: "{{ f0 }}" - register: disk_size_d1_c1_f0 - ignore_errors: True - -- debug: var=disk_size_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - not (disk_size_d1_c1_f0 is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/disk_type_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/disk_type_d1_c1_f0.yml deleted file mode 100644 index 3bd40895971..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/disk_type_d1_c1_f0.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: eagerzeroedthick - datastore: "{{ rw_datastore }}" - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: poweredoff - folder: F0 - register: disk_type_d1_c1_f0 - -- debug: var=disk_type_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - disk_type_d1_c1_f0 is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/linked_clone_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/linked_clone_d1_c1_f0.yml deleted file mode 100644 index 702ca59da7e..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/linked_clone_d1_c1_f0.yml +++ /dev/null @@ -1,100 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new linked clone without specifying snapshot_src - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ 'new_vm_' + item.name }}" - template: "{{ item.name }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - linked_clone: True - with_items: "{{ virtual_machines }}" - register: linked_clone_d1_c1_f0 - ignore_errors: True - -- debug: var=linked_clone_d1_c1_f0 - -- name: assert that changes were not made - assert: - that: - - "linked_clone_d1_c1_f0.results|map(attribute='changed')|unique|list == [false]" - -- name: create new linked clone without specifying linked_clone - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ 'new_vm_' + item.name }}" - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - snapshot_src: "snap_shot1" - with_items: "{{ virtual_machines }}" - register: linked_clone_d1_c1_f0 - ignore_errors: True - -- debug: var=linked_clone_d1_c1_f0 - -- name: assert that changes were not made - assert: - that: - - "linked_clone_d1_c1_f0.results|map(attribute='changed')|unique|list == [false]" - -# TODO: VCSIM: snapshot is not supported in current vcsim -# -#- name: create new linked clone with linked_clone and snapshot_src -# vmware_guest: -# validate_certs: False -# hostname: "{{ vcsim }}" -# username: "{{ vcsim_instance['json']['username'] }}" -# password: "{{ vcsim_instance['json']['password'] }}" -# name: "{{ 'new_vm_' + item|basename }}" -# template: "{{ item|basename }}" -# guest_id: centos64Guest -# datacenter: "{{ (item|basename).split('_')[0] }}" -# folder: "{{ item|dirname }}" -# snapshot_src: "snap_shot1" -# linked_clone: True -# with_items: "{{ vmlist['json'] }}" -# register: linked_clone_d1_c1_f0 -# ignore_errors: True - -#- debug: var=linked_clone_d1_c1_f0 - -#- name: assert that changes were made -# assert: -# that: -# - "linked_clone_d1_c1_f0.results|map(attribute='changed')|unique|list == [true]" - -# TODO: VCSIM: snapshot is not supported in current vcsim -# -#- name: create new linked clone with linked_clone and snapshot_src again -# vmware_guest: -# validate_certs: False -# hostname: "{{ vcsim }}" -# username: "{{ vcsim_instance['json']['username'] }}" -# password: "{{ vcsim_instance['json']['password'] }}" -# name: "{{ 'new_vm_' + item|basename }}" -# template: "{{ item|basename }}" -# guest_id: centos64Guest -# datacenter: "{{ (item|basename).split('_')[0] }}" -# folder: "{{ item|dirname }}" -# snapshot_src: "snap_shot1" -# linked_clone: True -# with_items: "{{ vmlist['json'] }}" -# register: linked_clone_d1_c1_f0 -# ignore_errors: True - -#- debug: var=linked_clone_d1_c1_f0 - -#- name: assert that changes were not made -# assert: -# that: -# - "linked_clone_d1_c1_f0.results|map(attribute='changed')|unique|list == [false]" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/mac_address_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/mac_address_d1_c1_f0.yml deleted file mode 100644 index 6e5a8d9217a..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/mac_address_d1_c1_f0.yml +++ /dev/null @@ -1,37 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create new VMs with manual MAC address - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: VM Network - ip: 192.168.10.12 - netmask: 255.255.255.0 - gateway: 192.168.10.254 - mac: aa:bb:cc:dd:aa:42 - state: poweredoff - folder: vm - register: clone_d1_c1_f0 - -- debug: var=clone_d1_c1_f0 - -- name: assert that changes were made - assert: - that: - - "clone_d1_c1_f0['instance']['hw_eth0']['addresstype'] == 'manual'" - - "clone_d1_c1_f0['instance']['hw_eth0']['macaddress'] == 'aa:bb:cc:dd:aa:42'" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/main.yml b/test/integration/targets/incidental_vmware_guest/tasks/main.yml deleted file mode 100644 index ef064dc5c10..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/main.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, James Tanner -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- import_role: - name: incidental_vmware_prepare_tests - vars: - setup_attach_host: true - setup_datacenter: true - setup_datastore: true - setup_dvswitch: true - setup_resource_pool: true - setup_virtualmachines: true - setup_dvs_portgroup: true - -- include_tasks: run_test_playbook.yml - with_items: '{{ vmware_guest_test_playbooks }}' - loop_control: - loop_var: test_playbook diff --git a/test/integration/targets/incidental_vmware_guest/tasks/max_connections.yml b/test/integration/targets/incidental_vmware_guest/tasks/max_connections.yml deleted file mode 100644 index d9ab6b6621e..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/max_connections.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2019, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- when: vcsim is not defined - block: - - &add_mk_conn - name: Create new VM with max_connections as 4 - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - max_connections: 4 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: present - folder: "{{ f0 }}" - register: mk_conn_result_0001 - - - debug: var=mk_conn_result_0001 - - - name: Assert that changes were made - assert: - that: - - mk_conn_result_0001 is changed - - - <<: *add_mk_conn - name: Again create new VMs again with max_connections as 4 - register: mk_conn_result_0002 - - - debug: var=mk_conn_result_0002 - - - name: Assert that changes were not made - assert: - that: - - not (mk_conn_result_0002 is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/mem_reservation.yml b/test/integration/targets/incidental_vmware_guest/tasks/mem_reservation.yml deleted file mode 100644 index a5a9762f62b..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/mem_reservation.yml +++ /dev/null @@ -1,125 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2019, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- when: vcsim is not defined - block: - - &add_mem_reserve - name: Create new VMs with mem_reservation as 0 - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - mem_reservation: 0 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: present - folder: "{{ virtual_machines[0].folder }}" - register: mem_reserve_result_0001 - - - debug: var=mem_reserve_result_0001 - - - name: Assert that changes were made - assert: - that: - - mem_reserve_result_0001 is changed - - - <<: *add_mem_reserve - name: Again create new VMs with mem_reservation as 0 - register: mem_reserve_result_0002 - - - debug: var=mem_reserve_result_0002 - - - name: Assert that changes were not made - assert: - that: - - not (mem_reserve_result_0002 is changed) - - - &add_memory_reserve - name: Create new VM with memory_reservation as 0 - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm2 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - memory_reservation: 0 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: present - folder: "{{ virtual_machines[0].folder }}" - register: memory_reserve_result_0003 - - - debug: var=memory_reserve_result_0003 - - - name: Assert that changes were made - assert: - that: - - memory_reserve_result_0003 is changed - - - <<: *add_memory_reserve - name: Again create new VMs with memory_reservation as 0 - register: memory_reserve_result_0004 - - - debug: var=memory_reserve_result_0004 - - - name: Assert that changes were not made - assert: - that: - - not (memory_reserve_result_0004 is changed) - - - &no_memory_reserve - name: Create new VMs without memory_reservation or mem_reservation - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm3 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - memory_reservation: 0 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: present - folder: "{{ virtual_machines[0].folder }}" - register: no_memory_reserve_result_0005 - - - debug: var=no_memory_reserve_result_0005 - - - name: Assert that changes were made - assert: - that: - - no_memory_reserve_result_0005 is changed - - - <<: *no_memory_reserve - name: Again create new VMs without memory_reservation or mem_reservation - register: no_memory_reserve_result_0006 - - - debug: var=no_memory_reserve_result_0006 - - - name: Assert that changes were not made - assert: - that: - - not (no_memory_reserve_result_0006 is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/network_negative_test.yml b/test/integration/targets/incidental_vmware_guest/tasks/network_negative_test.yml deleted file mode 100644 index 768e06b042d..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/network_negative_test.yml +++ /dev/null @@ -1,339 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- debug: var=f0 - -- name: create new VMs with non-existent network - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "Non existent VM" - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: non_existent_network - ignore_errors: yes - -- debug: var=non_existent_network - -- name: assert that no changes were not made - assert: - that: - - not (non_existent_network is changed) - - "'does not exist' in non_existent_network.msg" - -- name: create new VMs with network and with only IP - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - type: static - ip: 10.10.10.10 - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: no_netmask - ignore_errors: yes - -- debug: var=no_netmask - -- name: assert that no changes were not made - assert: - that: - - "not no_netmask.changed" - - "\"'netmask' is required if 'ip' is specified under VM network list.\" in no_netmask.msg" - -- name: create new VMs with network and with only netmask - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - type: static - netmask: 255.255.255.0 - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: no_ip - ignore_errors: yes - -- debug: var=no_ip - -- name: assert that changes were not made - assert: - that: - - "not no_ip.changed" - - "\"'ip' is required if 'netmask' is specified under VM network list.\" in no_ip.msg" - -- name: create new VMs with network and without network name - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - ip: 10.10.10.10 - netmask: 255.255.255 - type: static - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: no_network_name - ignore_errors: yes - -- debug: var=no_network_name - -- name: assert that no changes were not made - assert: - that: - - "not no_network_name.changed" - - "\"Please specify at least a network name or a VLAN name under VM network list.\" in no_network_name.msg" - -- name: create new VMs with network and without network name - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - vlan: non_existing_vlan - ip: 10.10.10.10 - netmask: 255.255.255 - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: no_network - ignore_errors: yes - -- debug: var=no_network - -- name: assert that changes were not made - assert: - that: - - "not no_network.changed" - - "\"VLAN 'non_existing_vlan' does not exist.\" in no_network.msg" - -- name: create new VMs with invalid device type - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - ip: 10.10.10.10 - netmask: 255.255.255 - device_type: abc - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: invalid_device_type - ignore_errors: yes - -- debug: var=invalid_device_type - -- name: assert that changes were not made - assert: - that: - - "not invalid_device_type.changed" - - "\"Device type specified 'abc' is not valid.\" in invalid_device_type.msg" - -- name: create new VMs with invalid device MAC address - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - ip: 10.10.10.10 - netmask: 255.255.255 - device_type: e1000 - mac: abcdef - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: invalid_mac - ignore_errors: yes - -- debug: var=invalid_mac - -- name: assert that changes were not made - assert: - that: - - "not invalid_mac.changed" - - "\"Device MAC address 'abcdef' is invalid.\" in invalid_mac.msg" - -- name: create new VMs with invalid network type - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - ip: 10.10.10.10 - netmask: 255.255.255 - device_type: e1000 - mac: 01:23:45:67:89:ab - type: aaaaa - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: invalid_network_type - ignore_errors: yes - -- debug: var=invalid_network_type - -- name: assert that changes were not made - assert: - that: - - "not invalid_network_type.changed" - - "\"Network type 'aaaaa' is not a valid parameter.\" in invalid_network_type.msg" - -- name: create new VMs with IP, netmask and network type as "DHCP" - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: new_vm - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - ip: 10.10.10.10 - netmask: 255.255.255 - device_type: e1000 - mac: 01:23:45:67:89:ab - type: dhcp - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: invalid_dhcp_network_type - ignore_errors: yes - -- debug: var=invalid_dhcp_network_type - -- name: assert that changes were not made - assert: - that: - - "not invalid_dhcp_network_type.changed" - - "\"Static IP information provided for network\" in invalid_dhcp_network_type.msg" - -- name: create new VMs with no network type which set network type as "DHCP" - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: "VM Network" - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: no_network_type - ignore_errors: yes - -- debug: var=no_network_type - -- name: assert that changes were made - assert: - that: - - "no_network_type.changed" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/network_with_device.yml b/test/integration/targets/incidental_vmware_guest/tasks/network_with_device.yml deleted file mode 100644 index 64b591adb78..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/network_with_device.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# Testcase to check #38605 -- name: Deploy VM first VM - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: False - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - name: test_vm1 - disk: - - size: 10mb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: 'VM Network' - device_type: "vmxnet3" - register: vm_result - -- debug: var=vm_result - -- assert: - that: - - "vm_result.changed" - -- name: Deploy VM again - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: False - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - name: test_vm1 - disk: - - size: 10mb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: 'VM Network' - device_type: "vmxnet3" - register: vm_result_again - -- debug: var=vm_result_again - -- assert: - that: - - not (vm_result_again is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/network_with_dvpg.yml b/test/integration/targets/incidental_vmware_guest/tasks/network_with_dvpg.yml deleted file mode 100644 index fba25aeee55..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/network_with_dvpg.yml +++ /dev/null @@ -1,152 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# Clone from existing VM with DVPG -- when: vcsim is not defined - block: - - name: Deploy VM from template - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - template: "{{ virtual_machines[0].name }}" - name: test_vm1 - disk: - - size: 1gb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: '{{ dvpg1 }}' - register: no_vm_result - - debug: var=no_vm_result - - assert: - that: - - no_vm_result is changed - - # New clone with DVPG - - name: Deploy new VM with DVPG - vmware_guest: - esxi_hostname: "{{ esxi_hosts[0] }}" - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - name: test_vm2 - disk: - - size: 1gb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: '{{ dvpg1 }}' - dvswitch_name: "{{ dvswitch1 }}" - register: no_vm_result - - debug: var=no_vm_result - - assert: - that: - - no_vm_result is changed - - - name: Deploy same VM again - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - name: test_vm2 - disk: - - size: 1gb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: '{{ dvpg1 }}' - register: no_vm_result - - debug: var=no_vm_result - - assert: - that: - - not (no_vm_result is changed) - - - name: Deploy new VM with DVPG with slash in name - vmware_guest: - esxi_hostname: "{{ esxi_hosts[0] }}" - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - name: test_vm3 - disk: - - size: 1gb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: '{{ dvpg_with_slash }}' - dvswitch_name: "{{ dvswitch1 }}" - register: no_vm_result - - debug: var=no_vm_result - - assert: - that: - - no_vm_result is changed - - - name: Deploy same VM again - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: "{{ dc1 }}" - state: poweredon - folder: "{{ f0 }}" - name: test_vm3 - disk: - - size: 1gb - datastore: "{{ rw_datastore }}" - guest_id: rhel7_64guest - hardware: - memory_mb: 128 - num_cpus: 1 - networks: - - name: '{{ dvpg_with_slash }}' - register: no_vm_result - - debug: var=no_vm_result - - assert: - that: - - not (no_vm_result is changed) - always: - - when: vcsim is not defined - name: Remove VM to free the portgroup - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - name: '{{ item }}' - force: yes - state: absent - with_items: - - test_vm1 - - test_vm2 - - test_vm3 diff --git a/test/integration/targets/incidental_vmware_guest/tasks/network_with_portgroup.yml b/test/integration/targets/incidental_vmware_guest/tasks/network_with_portgroup.yml deleted file mode 100644 index c9eb80186a6..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/network_with_portgroup.yml +++ /dev/null @@ -1,47 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde , Tim Steinbach -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: Add portgroup - vmware_dvs_portgroup: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - portgroup_name: "portgroup_network" - switch_name: "{{ dvswitch1 }}" - vlan_id: "1" - num_ports: 2 - portgroup_type: earlyBinding - state: present - register: dvsportgroup -- debug: var=dvsportgroup -- name: create new VMs with portgroup - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - disk: - - size: 3mb - type: thin - datastore: "{{ rw_datastore }}" - networks: - - name: portgroup_network - switch_name: "{{ dvswitch1 }}" - hardware: - num_cpus: 1 - memory_mb: 128 - state: poweredoff - folder: "{{ f0 }}" - register: vm_with_portgroup - ignore_errors: no - -- debug: var=vm_with_portgroup - -- assert: - that: - - vm_with_portgroup is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/non_existent_vm_ops.yml b/test/integration/targets/incidental_vmware_guest/tasks/non_existent_vm_ops.yml deleted file mode 100644 index 0815fdf9c6c..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/non_existent_vm_ops.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: Perform operation on non-existent VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "non_existent_vm" - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - state: poweredoff - register: non_existent_vm_ops - ignore_errors: yes -- debug: var=non_existent_vm_ops -- name: assert that changes were not made - assert: - that: - - not (non_existent_vm_ops is changed) - - "'msg' in non_existent_vm_ops" - - "'Unable to find the datastore with given parameters.' in non_existent_vm_ops.msg" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f0.yml deleted file mode 100644 index 6bddf568f74..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f0.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, James Tanner -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: create a VM with the poweroff status - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ item.name }}" - state: poweredoff - with_items: "{{ virtual_machines }}" - register: poweroff_d1_c1_f0 - -- debug: - var: poweroff_d1_c1_f0 - -- name: make sure changes were made - assert: - that: - - poweroff_d1_c1_f0.results[0].instance.hw_power_status == "poweredOff" - -- name: make sure no changes were made (the VMs are already off) - assert: - that: - - poweroff_d1_c1_f0.results[0].changed|bool == false diff --git a/test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f1.yml b/test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f1.yml deleted file mode 100644 index cb5ada078f9..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/poweroff_d1_c1_f1.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2017, James Tanner -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# https://github.com/ansible/ansible/issues/25011 -# Sending "-folders 1" to vcsim nests the datacenter under -# the folder so that the path prefix is no longer /vm -# -# /F0/DC0/vm/F0/DC0_H0_VM0 - -- name: set state to poweredoff on all VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ item.name }}" - state: poweredoff - folder: "{{ item.folder }}" - with_items: "{{ virtual_machines }}" - register: poweroff_d1_c1_f1 -- debug: var=poweroff_d1_c1_f1 diff --git a/test/integration/targets/incidental_vmware_guest/tasks/reconfig_vm_to_latest_version.yml b/test/integration/targets/incidental_vmware_guest/tasks/reconfig_vm_to_latest_version.yml deleted file mode 100644 index 619090dc0bb..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/reconfig_vm_to_latest_version.yml +++ /dev/null @@ -1,73 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2019, Pavan Bidkar -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# Skipping out idepotency test untill issue fixed in reconfigure_vm() become_method - -- name: Create VM with hardware version 12 - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos7_64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - datastore: '{{ rw_datastore }}' - hardware: - num_cpus: 4 - memory_mb: 1028 - version: 12 - state: present - register: create_vm_with_version_12 - -- name: assert that changes were made - assert: - that: - - create_vm_with_version_12 is changed - -- name: Deploy New VM with latest hardware version - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm2 - guest_id: centos7_64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - datastore: '{{ rw_datastore }}' - hardware: - num_cpus: 4 - memory_mb: 1028 - version: latest - state: present - register: deploy_vm_to_latest - -- name: assert that changes were made - assert: - that: - - deploy_vm_to_latest is changed - -- name: Upgrade VM to latest version - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos7_64Guest - datacenter: "{{ dc1 }}" - folder: "{{ f0 }}" - datastore: '{{ rw_datastore }}' - hardware: - num_cpus: 4 - memory_mb: 1028 - version: latest - state: present - register: upgrade_vm - -- name: assert that changes were made - assert: - that: - - upgrade_vm is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/remove_vm_from_inventory.yml b/test/integration/targets/incidental_vmware_guest/tasks/remove_vm_from_inventory.yml deleted file mode 100644 index 74da57d4b04..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/remove_vm_from_inventory.yml +++ /dev/null @@ -1,61 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2019, Pavan Bidkar -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- name: Create VM to unregister - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - guest_id: centos64Guest - datacenter: "{{ dc1 }}" - folder: F0 - hardware: - num_cpus: 1 - num_cpu_cores_per_socket: 1 - memory_mb: 128 - disk: - - size: 1gb - type: thin - datastore: "{{ rw_datastore }}" - state: present - register: create_vm_for_test - -- name: assert that changes were made - assert: - that: - - create_vm_for_test is changed - -- name: Remove VM from Inventory - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - delete_from_inventory: True - state: absent - register: remove_vm_from_inventory - -- name: assert that changes were made - assert: - that: - - remove_vm_from_inventory is changed - -- name: Remove VM again from Inventory - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: test_vm1 - delete_from_inventory: True - state: absent - register: remove_again_vm_from_inventory - -- name: assert that changes were made - assert: - that: - - not (remove_again_vm_from_inventory is changed) diff --git a/test/integration/targets/incidental_vmware_guest/tasks/run_test_playbook.yml b/test/integration/targets/incidental_vmware_guest/tasks/run_test_playbook.yml deleted file mode 100644 index d60dc394e16..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/run_test_playbook.yml +++ /dev/null @@ -1,17 +0,0 @@ -- block: - - include_tasks: '{{ test_playbook }}' - always: - - name: Remove VM - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no -# cluster: "{{ ccr1 }}" - name: '{{ item }}' - force: yes - state: absent - with_items: - - test_vm1 - - test_vm2 - - test_vm3 diff --git a/test/integration/targets/incidental_vmware_guest/tasks/template_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/template_d1_c1_f0.yml deleted file mode 100644 index 55e27c9dedd..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/template_d1_c1_f0.yml +++ /dev/null @@ -1,105 +0,0 @@ -- name: Create VMs with the poweredoff state - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - datacenter: "{{ dc1 }}" - validate_certs: no - folder: '{{ f0 }}' - name: 'test_vm1' - state: poweredoff - guest_id: debian8_64Guest - disk: - - size_gb: 1 - type: thin - datastore: '{{ rw_datastore }}' - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] fedora.iso" - networks: - - name: VM Network - -- name: ensure that VM1 are not flagged as templates - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - datacenter: "{{ dc1 }}" - folder: "{{ virtual_machines[1].folder }}" - name: "{{ virtual_machines[1].name }}" - state: present - is_template: False - register: no_template_initial - -- debug: var=no_template_initial - -- name: ensure no changes were made - assert: - that: - - not (no_template_initial is changed) - -- name: convert VM1 to template - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - datacenter: "{{ dc1 }}" - folder: "{{ virtual_machines[1].folder }}" - name: "{{ virtual_machines[1].name }}" - state: present - is_template: True - register: convert_to_template - -- debug: var=convert_to_template - -- name: ensure that changes were made - assert: - that: - - convert_to_template is changed - -- name: make double sure that VM1 is template - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - datacenter: "{{ dc1 }}" - folder: "{{ virtual_machines[1].folder }}" - name: "{{ virtual_machines[1].name }}" - state: present - is_template: True - register: still_templates - -- debug: var=still_templates - -- name: ensure that no changes were made - assert: - that: - - not (still_templates is changed) - -# To avoid the follow error of vcsim: VirtualMachine:vm-67 does not implement: MarkAsVirtualMachine -- when: vcsim is not defined - block: - - name: convert template back to VMs - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - datacenter: "{{ dc1 }}" - folder: "{{ virtual_machines[1].folder }}" - name: "{{ virtual_machines[1].name }}" - state: present - is_template: False - register: revert_to_vm - - debug: var=revert_to_vm - - name: ensure that changes were made - assert: - that: - - revert_to_vm is changed diff --git a/test/integration/targets/incidental_vmware_guest/tasks/vapp_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/vapp_d1_c1_f0.yml deleted file mode 100644 index bd83f97db61..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/vapp_d1_c1_f0.yml +++ /dev/null @@ -1,100 +0,0 @@ -# Test code for the vmware_guest module. -# Copyright: (c) 2018, goshkis -# Copyright: (c) 2019, Abhijeet Kasurde -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- &vapp_new_vm - name: Create test VM with vAPP settings - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "vm" - name: test_vm1 - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: centos64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: "{{ rw_datastore }}" - vapp_properties: - - id: prop_id1 - category: category - label: prop_label1 - type: string - value: prop_value1 - - id: prop_id2 - category: category - label: prop_label2 - type: string - value: prop_value2 - register: vapp_vm - -- debug: var=vapp_vm - -- name: assert the vApp propeties were created - assert: - that: - - "vapp_vm.failed == false" - - "vapp_vm.changed == true" - -- when: vcsim is not defined - block: - - <<: *vapp_new_vm - name: Try to create same VM with same vAPP settings - register: vapp_vm_no_change - - - debug: var=vapp_vm_no_change - - - name: Assert that vApp properties were not changed - assert: - that: - - "vapp_vm_no_change.failed == false" - - "not vapp_vm_no_change.changed" - -- &vapp_edit_vm - name: Edit one vApp property and removing another - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "vm" - name: test_vm1 - datacenter: "{{ dc1 }}" - vapp_properties: - - id: prop_id1 - operation: remove - - id: prop_id2 - value: prop_value3 - state: present - register: vapp_vm - -- debug: var=vapp_vm - -- name: assert the VM was changed - assert: - that: - - "vapp_vm.failed == false" - - "vapp_vm.changed == true" - -- when: vcsim is not defined - block: - - <<: *vapp_edit_vm - name: Try to edit VM with vApp settings - register: vapp_vm_no_change_edit - - - debug: var=vapp_vm_no_change_edit - - - name: assert the VM was changed - assert: - that: - - "vapp_vm_no_change_edit.failed == false" - - "vapp_vm_no_change_edit.changed == false" diff --git a/test/integration/targets/incidental_vmware_guest/tasks/windows_vbs_d1_c1_f0.yml b/test/integration/targets/incidental_vmware_guest/tasks/windows_vbs_d1_c1_f0.yml deleted file mode 100644 index 88a5757bf1d..00000000000 --- a/test/integration/targets/incidental_vmware_guest/tasks/windows_vbs_d1_c1_f0.yml +++ /dev/null @@ -1,93 +0,0 @@ -- name: Create Windows 10 VM with VBS enabled - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "{{ f0 }}" - name: vbs-Test - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: windows9_64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - virt_based_security: True - version: 14 - boot_firmware: efi - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: '{{ rw_datastore }}' - cdrom: - type: client - register: vbs_vm - -- debug: var=vbs_vm - -- name: assert the VM was created - assert: - that: - - "vbs_vm.failed == false" - - "vbs_vm.changed == true" - -- name: Create Windows Server 2016 VM without VBS enabled - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "{{ f0 }}" - name: vbs-Test2 - datacenter: "{{ dc1 }}" - cluster: "{{ ccr1 }}" - resource_pool: Resources - guest_id: windows9Server64Guest - hardware: - memory_mb: 128 - num_cpus: 1 - version: 14 - boot_firmware: efi - scsi: paravirtual - disk: - - size_mb: 128 - type: thin - datastore: '{{ rw_datastore }}' - cdrom: - type: client - register: vbs_vm - -- debug: var=vbs_vm - -- name: assert the VM was created - assert: - that: - - "vbs_vm.failed == false" - - "vbs_vm.changed == true" - -- name: Enable VBS for Windows Server 2016 VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - folder: "{{ f0 }}" - name: vbs-Test2 - datacenter: "{{ f0 }}" - disk: - - size_mb: 256 - type: thin - datastore: '{{ rw_datastore }}' - hardware: - virt_based_security: True - state: present - register: vbs_vm - -- debug: var=vbs_vm - -- name: assert the VM was changed - assert: - that: - - vbs_vm is changed diff --git a/test/integration/targets/incidental_vmware_host_hyperthreading/aliases b/test/integration/targets/incidental_vmware_host_hyperthreading/aliases deleted file mode 100644 index 0eb73d761dc..00000000000 --- a/test/integration/targets/incidental_vmware_host_hyperthreading/aliases +++ /dev/null @@ -1,3 +0,0 @@ -cloud/vcenter -shippable/vcenter/incidental -needs/target/incidental_vmware_prepare_tests diff --git a/test/integration/targets/incidental_vmware_host_hyperthreading/tasks/main.yml b/test/integration/targets/incidental_vmware_host_hyperthreading/tasks/main.yml deleted file mode 100644 index 4d9e5f76080..00000000000 --- a/test/integration/targets/incidental_vmware_host_hyperthreading/tasks/main.yml +++ /dev/null @@ -1,92 +0,0 @@ -# Test code for the vmware_host_hyperthreading module. -# Copyright: (c) 2018, Christian Kotte -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# Hyperthreading optimization is not available for hosts in vcsim -- import_role: - name: incidental_vmware_prepare_tests - vars: - setup_attach_host: true - - -- name: Enable Hyperthreading everywhere - vmware_host_hyperthreading: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - state: disabled - register: enable_hyperthreading_everywhere - ignore_errors: true - -- when: enable_hyperthreading_everywhere is succeeded - block: - - - name: Disable Hyperthreading for a given host - vmware_host_hyperthreading: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - esxi_hostname: '{{ esxi1 }}' - validate_certs: no - state: disabled - register: host_hyperthreading_info - - - debug: var=host_hyperthreading_info - - - assert: - that: - - host_hyperthreading_info is defined - - host_hyperthreading_info.changed - - - name: Disable Hyperthreading for a given host in check mode - vmware_host_hyperthreading: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - esxi_hostname: '{{ esxi1 }}' - validate_certs: no - state: disabled - register: host_hyperthreading_info_check_mode - check_mode: yes - - - debug: var=host_hyperthreading_info_check_mode - - - assert: - that: - - host_hyperthreading_info_check_mode is defined - - - name: Disable Hyperthreading for all hosts in given cluster - vmware_host_hyperthreading: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - cluster_name: "{{ ccr1 }}" - validate_certs: no - state: disabled - register: host_hyperthreading_info - - - debug: var=host_hyperthreading_info - - - assert: - that: - - host_hyperthreading_info is defined - - host_hyperthreading_info is changed - - - name: Enable Hyperthreading for all hosts in given cluster in check mode - vmware_host_hyperthreading: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - cluster_name: "{{ ccr1 }}" - validate_certs: no - state: enabled - register: host_hyperthreading_info_check_mode - check_mode: yes - - - debug: var=host_hyperthreading_info_check_mode - - - assert: - that: - - host_hyperthreading_info_check_mode is defined - - host_hyperthreading_info_check_mode.changed diff --git a/test/integration/targets/incidental_vmware_prepare_tests/aliases b/test/integration/targets/incidental_vmware_prepare_tests/aliases deleted file mode 100644 index 136c05e0d02..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/aliases +++ /dev/null @@ -1 +0,0 @@ -hidden diff --git a/test/integration/targets/incidental_vmware_prepare_tests/meta/main.yml b/test/integration/targets/incidental_vmware_prepare_tests/meta/main.yml deleted file mode 100644 index 61d3ffe4f94..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/meta/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -allow_duplicates: true diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/init_real_lab.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/init_real_lab.yml deleted file mode 100644 index 9450084fd17..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/init_real_lab.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -- include_tasks: teardown_with_esxi.yml - when: esxi_hosts|length > 0 -- include_tasks: teardown.yml - -- when: setup_esxi_instance is not defined - block: - - include_tasks: setup_datacenter.yml - - include_tasks: setup_cluster.yml - - include_tasks: setup_attach_hosts.yml - when: setup_attach_host is defined - - include_tasks: setup_datastore.yml - when: setup_datastore is defined - - include_tasks: setup_virtualmachines.yml - when: setup_virtualmachines is defined - - include_tasks: setup_switch.yml - when: setup_switch is defined - - include_tasks: setup_dvswitch.yml - when: setup_dvswitch is defined - - include_tasks: setup_resource_pool.yml - when: setup_resource_pool is defined - - include_tasks: setup_category.yml - when: setup_category is defined - - include_tasks: setup_tag.yml - when: setup_tag is defined - - include_tasks: setup_content_library.yml - when: setup_content_library is defined - - include_tasks: setup_dvs_portgroup.yml - when: setup_dvs_portgroup is defined diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/init_vcsim.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/init_vcsim.yml deleted file mode 100644 index 601bd5aad88..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/init_vcsim.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -- name: load vars - include_vars: - file: vcsim.yml - -- name: kill vcsim - uri: - url: http://{{ vcsim }}:5000/killall - -- name: start vcsim (all dressed) - uri: - url: http://{{ vcsim }}:5000/spawn?cluster=1&folder=1&ds=2 - register: vcsim_instance - when: setup_esxi_instance is not defined - -- name: start vcsim (ESXi only) - uri: - url: http://{{ vcsim }}:5000/spawn?esx=1 - register: vcsim_instance - when: setup_esxi_instance is defined - -# - name: get a list of Hosts from vcsim -# uri: -# url: http://{{ vcsim }}:5000/govc_find?filter=H -# register: vcsim_host_list - -# - name: get a list of Hosts from vcsim -# uri: -# url: http://{{ vcsim }}:5000/govc_find?filter=F -# register: vcsim_host_folder -# - debug: var=vcsim_host_folder - -- set_fact: - vcenter_hostname: "{{ vcsim }}" - vcenter_username: "user" - vcenter_password: "pass" - - -- name: set state to poweroff on all VMs - vmware_guest: - name: "{{ item.name }}" - state: poweredoff - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - with_items: "{{ virtual_machines + virtual_machines_in_cluster }}" - register: poweroff_d1_c1_f0 diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/main.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/main.yml deleted file mode 100644 index 91a6b9ca091..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/main.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- - -- name: load vmware common vars - include_vars: - file: common.yml - -- when: vcsim is not defined - block: - - when: esxi1_hostname is not defined and esxi2_hostname is not defined - include_vars: - file: vcenter_only.yml - - - when: esxi1_hostname is defined and esxi2_hostname is not defined - include_vars: - file: vcenter_1esxi.yml - - - when: esxi1_hostname is defined and esxi2_hostname is defined - include_vars: - file: vcenter_2esxi.yml - - - when: vcsim is not defined - include_tasks: init_real_lab.yml - -- when: vcsim is defined - include_tasks: init_vcsim.yml diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_attach_hosts.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_attach_hosts.yml deleted file mode 100644 index 6ca19b95b59..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_attach_hosts.yml +++ /dev/null @@ -1,30 +0,0 @@ -- fail: - msg: "No ESXi hosts defined. esxi_hosts is empty." - when: "esxi_hosts|length == 0" - -- name: Add ESXi Hosts to vCenter - vmware_host: - datacenter_name: '{{ dc1 }}' - cluster_name: '{{ ccr1 }}' - esxi_hostname: '{{ item }}' - esxi_username: '{{ esxi_user }}' - esxi_password: '{{ esxi_password }}' - state: add_or_reconnect - with_items: "{{ esxi_hosts }}" - -- name: Disable the Maintenance Mode - vmware_maintenancemode: - esxi_hostname: '{{ item }}' - state: absent - with_items: "{{ esxi_hosts }}" - -- name: Add Management Network VM Portgroup - vmware_portgroup: - hostname: '{{ item }}' - username: '{{ esxi_user }}' - password: '{{ esxi_password }}' - esxi_hostname: 'item' - switch: "vSwitch0" - portgroup: VM Network - validate_certs: no - with_items: "{{ esxi_hosts }}" diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_category.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_category.yml deleted file mode 100644 index bfd680172c0..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_category.yml +++ /dev/null @@ -1,5 +0,0 @@ -- name: Create a category for cluster - vmware_category: - category_name: '{{ cluster_category }}' - category_description: '{{ cluster_category }} description' - state: present diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_cluster.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_cluster.yml deleted file mode 100644 index 81653a53777..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_cluster.yml +++ /dev/null @@ -1,10 +0,0 @@ -- name: Create Cluster - vmware_cluster: - datacenter_name: '{{ dc1 }}' - cluster_name: '{{ ccr1 }}' - -- name: Enable DRS on Cluster - vmware_cluster_drs: - datacenter_name: '{{ dc1 }}' - cluster_name: '{{ ccr1 }}' - enable_drs: yes diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_content_library.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_content_library.yml deleted file mode 100644 index 26affd53fa3..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_content_library.yml +++ /dev/null @@ -1,7 +0,0 @@ -- name: Create Content Library - vmware_content_library_manager: - library_name: test-content-lib - library_description: 'Library created by the prepare_vmware_tests role' - library_type: local - datastore_name: '{{ rw_datastore }}' - state: present diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datacenter.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datacenter.yml deleted file mode 100644 index a5f3eafe511..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datacenter.yml +++ /dev/null @@ -1,11 +0,0 @@ -- name: Create Datacenter - vmware_datacenter: - datacenter_name: '{{ dc1 }}' - state: present - -- name: Create a VM folder on given Datacenter - vcenter_folder: - datacenter: '{{ dc1 }}' - folder_name: '{{ f0 }}' - folder_type: vm - state: present diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datastore.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datastore.yml deleted file mode 100644 index 5a628160168..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_datastore.yml +++ /dev/null @@ -1,42 +0,0 @@ ---- -- name: Mount NFS (ro_datastore) datastores to ESXi - vmware_host_datastore: - hostname: '{{ item }}' - username: '{{ esxi_user }}' - password: '{{ esxi_password }}' - datastore_name: '{{ ro_datastore }}' - datastore_type: '{{ infra.datastores[ro_datastore].type }}' - nfs_server: '{{ infra.datastores[ro_datastore].server }}' - nfs_path: '{{ infra.datastores[ro_datastore].path }}' - nfs_ro: '{{ infra.datastores[ro_datastore].ro }}' - state: present - validate_certs: no - with_items: "{{ esxi_hosts }}" - -- name: Mount NFS (rw_datastore) datastores on the ESXi - vmware_host_datastore: - hostname: '{{ item }}' - username: '{{ esxi_user }}' - password: '{{ esxi_password }}' - datastore_name: '{{ rw_datastore }}' - datastore_type: '{{ infra.datastores[rw_datastore].type }}' - nfs_server: '{{ infra.datastores[rw_datastore].server }}' - nfs_path: '{{ infra.datastores[rw_datastore].path }}' - nfs_ro: '{{ infra.datastores[rw_datastore].ro }}' - state: present - validate_certs: no - with_items: "{{ esxi_hosts }}" - -- vmware_host_scanhba: - refresh_storage: true - cluster_name: '{{ ccr1 }}' - -- name: The vcenter needs a bit of time to refresh the DS list - vmware_datastore_info: - validate_certs: false - cluster: '{{ ccr1 }}' - register: setup_datastore_datatstore_info - failed_when: setup_datastore_datatstore_info.datastores|selectattr('type', 'equalto', 'NFS')|list|length != 2 - until: setup_datastore_datatstore_info is succeeded - retries: 60 - delay: 1 diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvs_portgroup.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvs_portgroup.yml deleted file mode 100644 index c0e14fe5399..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvs_portgroup.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -- name: create basic DVS portgroup - vmware_dvs_portgroup: - switch_name: "{{ dvswitch1 }}" - portgroup_name: '{{ dvpg1 }}' - vlan_id: 0 - num_ports: 32 - portgroup_type: earlyBinding - state: present - -- name: Create the DVS PG with slash in name - vmware_dvs_portgroup: - portgroup_name: '{{ dvpg_with_slash }}' - switch_name: '{{ dvswitch1 }}' - vlan_id: 0 - num_ports: 120 - portgroup_type: earlyBinding - state: present diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvswitch.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvswitch.yml deleted file mode 100644 index ba36a461961..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_dvswitch.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -- name: Create the DVSwitch - vmware_dvswitch: - datacenter_name: '{{ dc1 }}' - switch_name: '{{ dvswitch1 }}' - switch_version: 6.0.0 - mtu: 9000 - uplink_quantity: 2 - discovery_proto: lldp - discovery_operation: both - state: present -- name: Attach the hosts to the DVSwitch - vmware_dvs_host: - esxi_hostname: "{{ item }}" - switch_name: '{{ dvswitch1 }}' - vmnics: - - vmnic1 - state: present - with_items: "{{ esxi_hosts }}" - when: setup_attach_host is defined diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_resource_pool.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_resource_pool.yml deleted file mode 100644 index 060785d17ab..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_resource_pool.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -- name: Add resource pool to vCenter - vmware_resource_pool: - datacenter: '{{ dc1 }}' - cluster: '{{ ccr1 }}' - resource_pool: DC0_C0_RP1 - mem_shares: normal - mem_limit: -1 - mem_reservation: 0 - mem_expandable_reservations: yes - cpu_shares: normal - cpu_limit: -1 - cpu_reservation: 0 - cpu_expandable_reservations: yes - state: present diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_switch.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_switch.yml deleted file mode 100644 index c63a28c52b0..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_switch.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: Add a VMware vSwitchs - vmware_vswitch: - esxi_hostname: '{{ item }}' - switch_name: "{{ switch1 }}" - state: present - with_items: "{{ esxi_hosts }}" diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_tag.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_tag.yml deleted file mode 100644 index 31b495c0f4a..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_tag.yml +++ /dev/null @@ -1,15 +0,0 @@ -- name: Get Category facts - vmware_category_info: - register: cat_info - -- name: Get Category id for {{ cluster_category }} - set_fact: - cluster_category_id: "{{ cat_info.tag_category_info[0].category_id }}" - -- name: Create a tag for cluster - vmware_tag: - category_id: '{{ cluster_category_id }}' - tag_name: '{{ cluster_tag }}' - tag_description: '{{ cluster_tag }} Description' - state: present - when: cluster_category_id is defined diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_virtualmachines.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_virtualmachines.yml deleted file mode 100644 index 8368f4b8134..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/setup_virtualmachines.yml +++ /dev/null @@ -1,46 +0,0 @@ ---- -- name: Create VMs - vmware_guest: - datacenter: "{{ dc1 }}" - folder: '{{ item.folder }}' - name: '{{ item.name }}' - state: poweredoff - guest_id: debian8_64Guest - disk: - - size_gb: 1 - type: thin - datastore: '{{ rw_datastore }}' - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] fedora.iso" - networks: - - name: VM Network - with_items: '{{ virtual_machines }}' - - -- name: Create VMs in cluster - vmware_guest: - datacenter: "{{ dc1 }}" - folder: '{{ item.folder }}' - cluster: '{{ item.cluster }}' - name: '{{ item.name }}' - state: poweredoff - guest_id: debian8_64Guest - disk: - - size_gb: 1 - type: thin - datastore: '{{ rw_datastore }}' - hardware: - memory_mb: 128 - num_cpus: 1 - scsi: paravirtual - cdrom: - type: iso - iso_path: "[{{ ro_datastore }}] fedora.iso" - networks: - - name: VM Network - with_items: '{{ virtual_machines_in_cluster }}' diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown.yml deleted file mode 100644 index aba390592ee..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -- name: Delete a datastore cluster to datacenter - vmware_datastore_cluster: - datacenter_name: "{{ dc1 }}" - datastore_cluster_name: '{{ item }}' - state: absent - with_items: - - DSC1 - - DSC2 - ignore_errors: yes - -- name: Remove the datacenter - vmware_datacenter: - datacenter_name: '{{ item }}' - state: absent - when: vcsim is not defined - with_items: - - '{{ dc1 }}' - - datacenter_0001 - -- name: kill vcsim - uri: - url: "http://{{ vcsim }}:5000/killall" - when: vcsim is defined diff --git a/test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown_with_esxi.yml b/test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown_with_esxi.yml deleted file mode 100644 index 2707847ef25..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/tasks/teardown_with_esxi.yml +++ /dev/null @@ -1,96 +0,0 @@ ---- -- name: Clean up the firewall rules - vmware_host_firewall_manager: - cluster_name: '{{ ccr1 }}' - rules: - - name: vvold - enabled: False - - name: CIMHttpServer - enabled: True - allowed_hosts: - all_ip: True - - name: NFC - enabled: True - allowed_hosts: - all_ip: True - ignore_errors: yes - -- name: Remove the VM prepared by prepare_vmware_tests - vmware_guest: - name: "{{ item.name }}" - force: yes - state: absent - with_items: '{{ virtual_machines + virtual_machines_in_cluster }}' - -- name: Remove the test_vm* VMs - vmware_guest: - name: "{{ item }}" - force: yes - state: absent - with_items: - - test_vm1 - - test_vm2 - - test_vm3 - -- name: Remove the DVS portgroups - vmware_dvs_portgroup: - switch_name: "{{ dvswitch1 }}" - portgroup_name: '{{ item }}' - vlan_id: 0 - num_ports: 32 - portgroup_type: earlyBinding - state: absent - loop: - - DC0_DVPG0 - - DVPG/1 - ignore_errors: yes - -- name: Remove the DVSwitch - vmware_dvswitch: - datacenter_name: '{{ dc1 }}' - state: absent - switch_name: '{{ item }}' - loop: - - '{{ dvswitch1 }}' - - dvswitch_0001 - - dvswitch_0002 - ignore_errors: yes - -- name: Remove the vSwitches - vmware_vswitch: - hostname: '{{ item }}' - username: '{{ esxi_user }}' - password: '{{ esxi_password }}' - switch_name: "{{ switch1 }}" - state: absent - with_items: "{{ esxi_hosts }}" - ignore_errors: yes - -- name: Remove ESXi Hosts to vCenter - vmware_host: - datacenter_name: '{{ dc1 }}' - cluster_name: ccr1 - esxi_hostname: '{{ item }}' - esxi_username: '{{ esxi_user }}' - esxi_password: '{{ esxi_password }}' - state: absent - with_items: "{{ esxi_hosts }}" - ignore_errors: yes - -- name: Umount NFS datastores to ESXi (1/2) - vmware_host_datastore: - hostname: '{{ item }}' - username: '{{ esxi_user }}' - password: '{{ esxi_password }}' - datastore_name: '{{ ro_datastore }}' - state: absent - with_items: "{{ esxi_hosts }}" - -- name: Umount NFS datastores to ESXi (2/2) - vmware_host_datastore: - hostname: '{{ item }}' - username: '{{ esxi_user }}' - password: '{{ esxi_password }}' - datastore_name: '{{ rw_datastore }}' - state: absent - with_items: "{{ esxi_hosts }}" diff --git a/test/integration/targets/incidental_vmware_prepare_tests/vars/common.yml b/test/integration/targets/incidental_vmware_prepare_tests/vars/common.yml deleted file mode 100644 index bfe5a30fb52..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/vars/common.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -dc1: DC0 -ccr1: DC0_C0 -f0: F0 -switch1: switch1 -esxi1: '{{ esxi_hosts[0] }}' -esxi2: '{{ esxi_hosts[1] }}' -esxi3: '{{ esxi_hosts[2] }}' -dvswitch1: DVS0 -esxi_user: root -dvpg1: DC0_DVPG0 -dvpg_with_slash: DVPG/1 diff --git a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_1esxi.yml b/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_1esxi.yml deleted file mode 100644 index 45e94331f9b..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_1esxi.yml +++ /dev/null @@ -1,33 +0,0 @@ ---- -esxi_hosts: - - esxi1.test -rw_datastore: rw_datastore -ro_datastore: ro_datastore -esxi_password: '{{ esxi1_password }}' -esxi_user: '{{ esxi1_username }}' -infra: - datastores: - rw_datastore: - type: nfs - server: datastore.test - path: /srv/share/vms - ro: false - ro_datastore: - type: nfs - server: datastore.test - path: /srv/share/isos - ro: true -virtual_machines: - - name: DC0_H0_VM0 - folder: '{{ f0 }}' - - name: DC0_H0_VM1 - folder: '{{ f0 }}' -virtual_machines_in_cluster: - - name: DC0_C0_RP0_VM0 - folder: '{{ f0 }}' - cluster: '{{ ccr1 }}' - - name: DC0_C0_RP0_VM1 - folder: '{{ f0 }}' - cluster: '{{ ccr1 }}' -cluster_tag: test_cluster_tag_0001 -cluster_category: test_cluster_cat_0001 diff --git a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_2esxi.yml b/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_2esxi.yml deleted file mode 100644 index 6b0203b4ac7..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_2esxi.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -esxi_hosts: - - esxi1.test - - esxi2.test -rw_datastore: rw_datastore -ro_datastore: ro_datastore -esxi_password: '{{ esxi1_password }}' -esxi_user: '{{ esxi1_username }}' -infra: - datastores: - rw_datastore: - type: nfs - server: datastore.test - path: /srv/share/vms - ro: false - ro_datastore: - type: nfs - server: datastore.test - path: /srv/share/isos - ro: true -virtual_machines: - - name: DC0_H0_VM0 - folder: '{{ f0 }}' - - name: DC0_H0_VM1 - folder: '{{ f0 }}' -virtual_machines_in_cluster: - - name: DC0_C0_RP0_VM0 - folder: '{{ f0 }}' - cluster: '{{ ccr1 }}' - - name: DC0_C0_RP0_VM1 - folder: '{{ f0 }}' - cluster: '{{ ccr1 }}' -cluster_tag: test_cluster_tag_0001 -cluster_category: test_cluster_cat_0001 diff --git a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_only.yml b/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_only.yml deleted file mode 100644 index 58560b5619f..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcenter_only.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -esxi_hosts: [] -infra: -virtual_machines: [] -virtual_machines_in_cluster: [] -#esxi_password: '' \ No newline at end of file diff --git a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcsim.yml b/test/integration/targets/incidental_vmware_prepare_tests/vars/vcsim.yml deleted file mode 100644 index ee783c1038b..00000000000 --- a/test/integration/targets/incidental_vmware_prepare_tests/vars/vcsim.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -esxi_hosts: - - DC0_C0_H0 - - DC0_C0_H1 - - DC0_C0_H2 -esxi_password: 'pass' -esxi_user: 'user' -rw_datastore: LocalDS_0 -ro_datastore: LocalDS_1 -virtual_machines: - - name: DC0_H0_VM0 - folder: /F0/DC0/vm/F0 - - name: DC0_H0_VM1 - folder: /F0/DC0/vm/F0 -virtual_machines_in_cluster: - - name: DC0_C0_RP0_VM0 - cluster: '{{ ccr1 }}' - - name: DC0_C0_RP0_VM1 - cluster: '{{ ccr1 }}' diff --git a/test/integration/targets/inventory_script/aliases b/test/integration/targets/inventory_script/aliases new file mode 100644 index 00000000000..a6dafcf8cd8 --- /dev/null +++ b/test/integration/targets/inventory_script/aliases @@ -0,0 +1 @@ +shippable/posix/group1 diff --git a/test/integration/targets/inventory_script/inventory.json b/test/integration/targets/inventory_script/inventory.json new file mode 100644 index 00000000000..5046a9a83c3 --- /dev/null +++ b/test/integration/targets/inventory_script/inventory.json @@ -0,0 +1,1045 @@ +{ + "None": { + "hosts": [ + "DC0_C0_RP0_VM0_cd0681bf-2f18-5c00-9b9b-8197c0095348", + "DC0_C0_RP0_VM1_f7c371d6-2003-5a48-9859-3bc9a8b08908", + "DC0_H0_VM0_265104de-1472-547c-b873-6dc7883fb6cb", + "DC0_H0_VM1_39365506-5a0a-5fd0-be10-9586ad53aaad" + ] + }, + "_meta": { + "hostvars": { + "DC0_C0_RP0_VM0_cd0681bf-2f18-5c00-9b9b-8197c0095348": { + "alarmactionsenabled": null, + "ansible_host": "None", + "ansible_ssh_host": "None", + "ansible_uuid": "239fb366-6d93-430e-939a-0b6ab272d98f", + "availablefield": [], + "capability": { + "bootoptionssupported": false, + "bootretryoptionssupported": false, + "changetrackingsupported": false, + "consolepreferencessupported": false, + "cpufeaturemasksupported": false, + "disablesnapshotssupported": false, + "diskonlysnapshotonsuspendedvmsupported": null, + "disksharessupported": false, + "dynamicproperty": [], + "dynamictype": null, + "featurerequirementsupported": false, + "guestautolocksupported": false, + "hostbasedreplicationsupported": false, + "locksnapshotssupported": false, + "memoryreservationlocksupported": false, + "memorysnapshotssupported": false, + "multiplecorespersocketsupported": false, + "multiplesnapshotssupported": false, + "nestedhvsupported": false, + "npivwwnonnonrdmvmsupported": false, + "pervmevcsupported": null, + "poweredoffsnapshotssupported": false, + "poweredonmonitortypechangesupported": false, + "quiescedsnapshotssupported": false, + "recordreplaysupported": false, + "reverttosnapshotsupported": false, + "s1acpimanagementsupported": false, + "securebootsupported": null, + "sesparsedisksupported": false, + "settingdisplaytopologysupported": false, + "settingscreenresolutionsupported": false, + "settingvideoramsizesupported": false, + "snapshotconfigsupported": false, + "snapshotoperationssupported": false, + "swapplacementsupported": false, + "toolsautoupdatesupported": false, + "toolssynctimesupported": false, + "virtualexecusageignored": null, + "virtualmmuusageignored": null, + "virtualmmuusagesupported": false, + "vmnpivwwndisablesupported": false, + "vmnpivwwnsupported": false, + "vmnpivwwnupdatesupported": false, + "vpmcsupported": false + }, + "config": { + "alternateguestname": "", + "annotation": null, + "bootoptions": null, + "changetrackingenabled": null, + "changeversion": "", + "consolepreferences": null, + "contentlibiteminfo": null, + "cpuaffinity": null, + "cpuallocation": {}, + "cpufeaturemask": [], + "cpuhotaddenabled": null, + "cpuhotremoveenabled": null, + "createdate": null, + "datastoreurl": [], + "defaultpowerops": {}, + "dynamicproperty": [], + "dynamictype": null, + "extraconfig": [], + "files": {}, + "firmware": null, + "flags": {}, + "forkconfiginfo": null, + "ftinfo": null, + "guestautolockenabled": null, + "guestfullname": "otherGuest", + "guestid": "otherGuest", + "guestintegrityinfo": null, + "guestmonitoringmodeinfo": null, + "hardware": {}, + "hotplugmemoryincrementsize": null, + "hotplugmemorylimit": null, + "initialoverhead": null, + "instanceuuid": "bfff331f-7f07-572d-951e-edd3701dc061", + "keyid": null, + "latencysensitivity": null, + "locationid": null, + "managedby": null, + "maxmksconnections": null, + "memoryaffinity": null, + "memoryallocation": {}, + "memoryhotaddenabled": null, + "memoryreservationlockedtomax": null, + "messagebustunnelenabled": null, + "migrateencryption": null, + "modified": {}, + "name": "DC0_C0_RP0_VM0", + "nestedhvenabled": null, + "networkshaper": null, + "npivdesirednodewwns": null, + "npivdesiredportwwns": null, + "npivnodeworldwidename": [], + "npivonnonrdmdisks": null, + "npivportworldwidename": [], + "npivtemporarydisabled": null, + "npivworldwidenametype": null, + "repconfig": null, + "scheduledhardwareupgradeinfo": null, + "sgxinfo": null, + "swapplacement": null, + "swapstorageobjectid": null, + "template": false, + "tools": {}, + "uuid": "cd0681bf-2f18-5c00-9b9b-8197c0095348", + "vappconfig": null, + "vassertsenabled": null, + "vcpuconfig": [], + "version": "vmx-13", + "vflashcachereservation": null, + "vmstorageobjectid": null, + "vmxconfigchecksum": null, + "vpmcenabled": null + }, + "configissue": [], + "configstatus": "green", + "customvalue": [], + "datastore": [ + { + "_moId": "/tmp/govcsim-DC0-LocalDS_0-949174843@folder-5", + "name": "LocalDS_0" + } + ], + "effectiverole": [ + -1 + ], + "guest": { + "appheartbeatstatus": null, + "appstate": null, + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "generationinfo": [], + "guestfamily": null, + "guestfullname": null, + "guestid": null, + "guestkernelcrashed": null, + "guestoperationsready": null, + "gueststate": "", + "gueststatechangesupported": null, + "hostname": null, + "hwversion": null, + "interactiveguestoperationsready": null, + "ipaddress": null, + "ipstack": [], + "net": [], + "screen": null, + "toolsinstalltype": null, + "toolsrunningstatus": "guestToolsNotRunning", + "toolsstatus": "toolsNotInstalled", + "toolsversion": "0", + "toolsversionstatus": null, + "toolsversionstatus2": null + }, + "guestheartbeatstatus": null, + "layout": { + "configfile": [], + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "logfile": [], + "snapshot": [], + "swapfile": null + }, + "layoutex": { + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "file": [], + "snapshot": [], + "timestamp": {} + }, + "name": "DC0_C0_RP0_VM0", + "network": [], + "overallstatus": "green", + "parentvapp": null, + "permission": [], + "recenttask": [], + "resourcepool": { + "_moId": "resgroup-26", + "name": "Resources" + }, + "rootsnapshot": [], + "runtime": { + "boottime": null, + "cleanpoweroff": null, + "connectionstate": "connected", + "consolidationneeded": false, + "cryptostate": null, + "dasvmprotection": null, + "device": [], + "dynamicproperty": [], + "dynamictype": null, + "faulttolerancestate": null, + "featuremask": [], + "featurerequirement": [], + "host": { + "_moId": "host-47", + "name": "DC0_C0_H2" + }, + "instantclonefrozen": null, + "maxcpuusage": null, + "maxmemoryusage": null, + "memoryoverhead": null, + "minrequiredevcmodekey": null, + "needsecondaryreason": null, + "nummksconnections": 0, + "offlinefeaturerequirement": [], + "onlinestandby": false, + "paused": null, + "powerstate": "poweredOn", + "question": null, + "quiescedforkparent": null, + "recordreplaystate": null, + "snapshotinbackground": null, + "suspendinterval": null, + "suspendtime": null, + "toolsinstallermounted": false, + "vflashcacheallocation": null + }, + "snapshot": null, + "storage": { + "dynamicproperty": [], + "dynamictype": null, + "perdatastoreusage": [], + "timestamp": {} + }, + "summary": { + "config": {}, + "customvalue": [], + "dynamicproperty": [], + "dynamictype": null, + "guest": {}, + "overallstatus": "green", + "quickstats": {}, + "runtime": {}, + "storage": {}, + "vm": {} + }, + "tag": [], + "triggeredalarmstate": [], + "value": [] + }, + "DC0_C0_RP0_VM1_f7c371d6-2003-5a48-9859-3bc9a8b08908": { + "alarmactionsenabled": null, + "ansible_host": "None", + "ansible_ssh_host": "None", + "ansible_uuid": "64b6ca93-f35f-4749-abeb-fc1fabae6c79", + "availablefield": [], + "capability": { + "bootoptionssupported": false, + "bootretryoptionssupported": false, + "changetrackingsupported": false, + "consolepreferencessupported": false, + "cpufeaturemasksupported": false, + "disablesnapshotssupported": false, + "diskonlysnapshotonsuspendedvmsupported": null, + "disksharessupported": false, + "dynamicproperty": [], + "dynamictype": null, + "featurerequirementsupported": false, + "guestautolocksupported": false, + "hostbasedreplicationsupported": false, + "locksnapshotssupported": false, + "memoryreservationlocksupported": false, + "memorysnapshotssupported": false, + "multiplecorespersocketsupported": false, + "multiplesnapshotssupported": false, + "nestedhvsupported": false, + "npivwwnonnonrdmvmsupported": false, + "pervmevcsupported": null, + "poweredoffsnapshotssupported": false, + "poweredonmonitortypechangesupported": false, + "quiescedsnapshotssupported": false, + "recordreplaysupported": false, + "reverttosnapshotsupported": false, + "s1acpimanagementsupported": false, + "securebootsupported": null, + "sesparsedisksupported": false, + "settingdisplaytopologysupported": false, + "settingscreenresolutionsupported": false, + "settingvideoramsizesupported": false, + "snapshotconfigsupported": false, + "snapshotoperationssupported": false, + "swapplacementsupported": false, + "toolsautoupdatesupported": false, + "toolssynctimesupported": false, + "virtualexecusageignored": null, + "virtualmmuusageignored": null, + "virtualmmuusagesupported": false, + "vmnpivwwndisablesupported": false, + "vmnpivwwnsupported": false, + "vmnpivwwnupdatesupported": false, + "vpmcsupported": false + }, + "config": { + "alternateguestname": "", + "annotation": null, + "bootoptions": null, + "changetrackingenabled": null, + "changeversion": "", + "consolepreferences": null, + "contentlibiteminfo": null, + "cpuaffinity": null, + "cpuallocation": {}, + "cpufeaturemask": [], + "cpuhotaddenabled": null, + "cpuhotremoveenabled": null, + "createdate": null, + "datastoreurl": [], + "defaultpowerops": {}, + "dynamicproperty": [], + "dynamictype": null, + "extraconfig": [], + "files": {}, + "firmware": null, + "flags": {}, + "forkconfiginfo": null, + "ftinfo": null, + "guestautolockenabled": null, + "guestfullname": "otherGuest", + "guestid": "otherGuest", + "guestintegrityinfo": null, + "guestmonitoringmodeinfo": null, + "hardware": {}, + "hotplugmemoryincrementsize": null, + "hotplugmemorylimit": null, + "initialoverhead": null, + "instanceuuid": "6132d223-1566-5921-bc3b-df91ece09a4d", + "keyid": null, + "latencysensitivity": null, + "locationid": null, + "managedby": null, + "maxmksconnections": null, + "memoryaffinity": null, + "memoryallocation": {}, + "memoryhotaddenabled": null, + "memoryreservationlockedtomax": null, + "messagebustunnelenabled": null, + "migrateencryption": null, + "modified": {}, + "name": "DC0_C0_RP0_VM1", + "nestedhvenabled": null, + "networkshaper": null, + "npivdesirednodewwns": null, + "npivdesiredportwwns": null, + "npivnodeworldwidename": [], + "npivonnonrdmdisks": null, + "npivportworldwidename": [], + "npivtemporarydisabled": null, + "npivworldwidenametype": null, + "repconfig": null, + "scheduledhardwareupgradeinfo": null, + "sgxinfo": null, + "swapplacement": null, + "swapstorageobjectid": null, + "template": false, + "tools": {}, + "uuid": "f7c371d6-2003-5a48-9859-3bc9a8b08908", + "vappconfig": null, + "vassertsenabled": null, + "vcpuconfig": [], + "version": "vmx-13", + "vflashcachereservation": null, + "vmstorageobjectid": null, + "vmxconfigchecksum": null, + "vpmcenabled": null + }, + "configissue": [], + "configstatus": "green", + "customvalue": [], + "datastore": [ + { + "_moId": "/tmp/govcsim-DC0-LocalDS_0-949174843@folder-5", + "name": "LocalDS_0" + } + ], + "effectiverole": [ + -1 + ], + "guest": { + "appheartbeatstatus": null, + "appstate": null, + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "generationinfo": [], + "guestfamily": null, + "guestfullname": null, + "guestid": null, + "guestkernelcrashed": null, + "guestoperationsready": null, + "gueststate": "", + "gueststatechangesupported": null, + "hostname": null, + "hwversion": null, + "interactiveguestoperationsready": null, + "ipaddress": null, + "ipstack": [], + "net": [], + "screen": null, + "toolsinstalltype": null, + "toolsrunningstatus": "guestToolsNotRunning", + "toolsstatus": "toolsNotInstalled", + "toolsversion": "0", + "toolsversionstatus": null, + "toolsversionstatus2": null + }, + "guestheartbeatstatus": null, + "layout": { + "configfile": [], + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "logfile": [], + "snapshot": [], + "swapfile": null + }, + "layoutex": { + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "file": [], + "snapshot": [], + "timestamp": {} + }, + "name": "DC0_C0_RP0_VM1", + "network": [], + "overallstatus": "green", + "parentvapp": null, + "permission": [], + "recenttask": [], + "resourcepool": { + "_moId": "resgroup-26", + "name": "Resources" + }, + "rootsnapshot": [], + "runtime": { + "boottime": null, + "cleanpoweroff": null, + "connectionstate": "connected", + "consolidationneeded": false, + "cryptostate": null, + "dasvmprotection": null, + "device": [], + "dynamicproperty": [], + "dynamictype": null, + "faulttolerancestate": null, + "featuremask": [], + "featurerequirement": [], + "host": { + "_moId": "host-33", + "name": "DC0_C0_H0" + }, + "instantclonefrozen": null, + "maxcpuusage": null, + "maxmemoryusage": null, + "memoryoverhead": null, + "minrequiredevcmodekey": null, + "needsecondaryreason": null, + "nummksconnections": 0, + "offlinefeaturerequirement": [], + "onlinestandby": false, + "paused": null, + "powerstate": "poweredOn", + "question": null, + "quiescedforkparent": null, + "recordreplaystate": null, + "snapshotinbackground": null, + "suspendinterval": null, + "suspendtime": null, + "toolsinstallermounted": false, + "vflashcacheallocation": null + }, + "snapshot": null, + "storage": { + "dynamicproperty": [], + "dynamictype": null, + "perdatastoreusage": [], + "timestamp": {} + }, + "summary": { + "config": {}, + "customvalue": [], + "dynamicproperty": [], + "dynamictype": null, + "guest": {}, + "overallstatus": "green", + "quickstats": {}, + "runtime": {}, + "storage": {}, + "vm": {} + }, + "tag": [], + "triggeredalarmstate": [], + "value": [] + }, + "DC0_H0_VM0_265104de-1472-547c-b873-6dc7883fb6cb": { + "alarmactionsenabled": null, + "ansible_host": "None", + "ansible_ssh_host": "None", + "ansible_uuid": "6616671b-16b0-494c-8201-737ca506790b", + "availablefield": [], + "capability": { + "bootoptionssupported": false, + "bootretryoptionssupported": false, + "changetrackingsupported": false, + "consolepreferencessupported": false, + "cpufeaturemasksupported": false, + "disablesnapshotssupported": false, + "diskonlysnapshotonsuspendedvmsupported": null, + "disksharessupported": false, + "dynamicproperty": [], + "dynamictype": null, + "featurerequirementsupported": false, + "guestautolocksupported": false, + "hostbasedreplicationsupported": false, + "locksnapshotssupported": false, + "memoryreservationlocksupported": false, + "memorysnapshotssupported": false, + "multiplecorespersocketsupported": false, + "multiplesnapshotssupported": false, + "nestedhvsupported": false, + "npivwwnonnonrdmvmsupported": false, + "pervmevcsupported": null, + "poweredoffsnapshotssupported": false, + "poweredonmonitortypechangesupported": false, + "quiescedsnapshotssupported": false, + "recordreplaysupported": false, + "reverttosnapshotsupported": false, + "s1acpimanagementsupported": false, + "securebootsupported": null, + "sesparsedisksupported": false, + "settingdisplaytopologysupported": false, + "settingscreenresolutionsupported": false, + "settingvideoramsizesupported": false, + "snapshotconfigsupported": false, + "snapshotoperationssupported": false, + "swapplacementsupported": false, + "toolsautoupdatesupported": false, + "toolssynctimesupported": false, + "virtualexecusageignored": null, + "virtualmmuusageignored": null, + "virtualmmuusagesupported": false, + "vmnpivwwndisablesupported": false, + "vmnpivwwnsupported": false, + "vmnpivwwnupdatesupported": false, + "vpmcsupported": false + }, + "config": { + "alternateguestname": "", + "annotation": null, + "bootoptions": null, + "changetrackingenabled": null, + "changeversion": "", + "consolepreferences": null, + "contentlibiteminfo": null, + "cpuaffinity": null, + "cpuallocation": {}, + "cpufeaturemask": [], + "cpuhotaddenabled": null, + "cpuhotremoveenabled": null, + "createdate": null, + "datastoreurl": [], + "defaultpowerops": {}, + "dynamicproperty": [], + "dynamictype": null, + "extraconfig": [], + "files": {}, + "firmware": null, + "flags": {}, + "forkconfiginfo": null, + "ftinfo": null, + "guestautolockenabled": null, + "guestfullname": "otherGuest", + "guestid": "otherGuest", + "guestintegrityinfo": null, + "guestmonitoringmodeinfo": null, + "hardware": {}, + "hotplugmemoryincrementsize": null, + "hotplugmemorylimit": null, + "initialoverhead": null, + "instanceuuid": "b4689bed-97f0-5bcd-8a4c-07477cc8f06f", + "keyid": null, + "latencysensitivity": null, + "locationid": null, + "managedby": null, + "maxmksconnections": null, + "memoryaffinity": null, + "memoryallocation": {}, + "memoryhotaddenabled": null, + "memoryreservationlockedtomax": null, + "messagebustunnelenabled": null, + "migrateencryption": null, + "modified": {}, + "name": "DC0_H0_VM0", + "nestedhvenabled": null, + "networkshaper": null, + "npivdesirednodewwns": null, + "npivdesiredportwwns": null, + "npivnodeworldwidename": [], + "npivonnonrdmdisks": null, + "npivportworldwidename": [], + "npivtemporarydisabled": null, + "npivworldwidenametype": null, + "repconfig": null, + "scheduledhardwareupgradeinfo": null, + "sgxinfo": null, + "swapplacement": null, + "swapstorageobjectid": null, + "template": false, + "tools": {}, + "uuid": "265104de-1472-547c-b873-6dc7883fb6cb", + "vappconfig": null, + "vassertsenabled": null, + "vcpuconfig": [], + "version": "vmx-13", + "vflashcachereservation": null, + "vmstorageobjectid": null, + "vmxconfigchecksum": null, + "vpmcenabled": null + }, + "configissue": [], + "configstatus": "green", + "customvalue": [], + "datastore": [ + { + "_moId": "/tmp/govcsim-DC0-LocalDS_0-949174843@folder-5", + "name": "LocalDS_0" + } + ], + "effectiverole": [ + -1 + ], + "guest": { + "appheartbeatstatus": null, + "appstate": null, + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "generationinfo": [], + "guestfamily": null, + "guestfullname": null, + "guestid": null, + "guestkernelcrashed": null, + "guestoperationsready": null, + "gueststate": "", + "gueststatechangesupported": null, + "hostname": null, + "hwversion": null, + "interactiveguestoperationsready": null, + "ipaddress": null, + "ipstack": [], + "net": [], + "screen": null, + "toolsinstalltype": null, + "toolsrunningstatus": "guestToolsNotRunning", + "toolsstatus": "toolsNotInstalled", + "toolsversion": "0", + "toolsversionstatus": null, + "toolsversionstatus2": null + }, + "guestheartbeatstatus": null, + "layout": { + "configfile": [], + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "logfile": [], + "snapshot": [], + "swapfile": null + }, + "layoutex": { + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "file": [], + "snapshot": [], + "timestamp": {} + }, + "name": "DC0_H0_VM0", + "network": [], + "overallstatus": "green", + "parentvapp": null, + "permission": [], + "recenttask": [], + "resourcepool": { + "_moId": "resgroup-22", + "name": "Resources" + }, + "rootsnapshot": [], + "runtime": { + "boottime": null, + "cleanpoweroff": null, + "connectionstate": "connected", + "consolidationneeded": false, + "cryptostate": null, + "dasvmprotection": null, + "device": [], + "dynamicproperty": [], + "dynamictype": null, + "faulttolerancestate": null, + "featuremask": [], + "featurerequirement": [], + "host": { + "_moId": "host-21", + "name": "DC0_H0" + }, + "instantclonefrozen": null, + "maxcpuusage": null, + "maxmemoryusage": null, + "memoryoverhead": null, + "minrequiredevcmodekey": null, + "needsecondaryreason": null, + "nummksconnections": 0, + "offlinefeaturerequirement": [], + "onlinestandby": false, + "paused": null, + "powerstate": "poweredOn", + "question": null, + "quiescedforkparent": null, + "recordreplaystate": null, + "snapshotinbackground": null, + "suspendinterval": null, + "suspendtime": null, + "toolsinstallermounted": false, + "vflashcacheallocation": null + }, + "snapshot": null, + "storage": { + "dynamicproperty": [], + "dynamictype": null, + "perdatastoreusage": [], + "timestamp": {} + }, + "summary": { + "config": {}, + "customvalue": [], + "dynamicproperty": [], + "dynamictype": null, + "guest": {}, + "overallstatus": "green", + "quickstats": {}, + "runtime": {}, + "storage": {}, + "vm": {} + }, + "tag": [], + "triggeredalarmstate": [], + "value": [] + }, + "DC0_H0_VM1_39365506-5a0a-5fd0-be10-9586ad53aaad": { + "alarmactionsenabled": null, + "ansible_host": "None", + "ansible_ssh_host": "None", + "ansible_uuid": "50401ff9-720a-4166-b9e6-d7cd0d9a4dc9", + "availablefield": [], + "capability": { + "bootoptionssupported": false, + "bootretryoptionssupported": false, + "changetrackingsupported": false, + "consolepreferencessupported": false, + "cpufeaturemasksupported": false, + "disablesnapshotssupported": false, + "diskonlysnapshotonsuspendedvmsupported": null, + "disksharessupported": false, + "dynamicproperty": [], + "dynamictype": null, + "featurerequirementsupported": false, + "guestautolocksupported": false, + "hostbasedreplicationsupported": false, + "locksnapshotssupported": false, + "memoryreservationlocksupported": false, + "memorysnapshotssupported": false, + "multiplecorespersocketsupported": false, + "multiplesnapshotssupported": false, + "nestedhvsupported": false, + "npivwwnonnonrdmvmsupported": false, + "pervmevcsupported": null, + "poweredoffsnapshotssupported": false, + "poweredonmonitortypechangesupported": false, + "quiescedsnapshotssupported": false, + "recordreplaysupported": false, + "reverttosnapshotsupported": false, + "s1acpimanagementsupported": false, + "securebootsupported": null, + "sesparsedisksupported": false, + "settingdisplaytopologysupported": false, + "settingscreenresolutionsupported": false, + "settingvideoramsizesupported": false, + "snapshotconfigsupported": false, + "snapshotoperationssupported": false, + "swapplacementsupported": false, + "toolsautoupdatesupported": false, + "toolssynctimesupported": false, + "virtualexecusageignored": null, + "virtualmmuusageignored": null, + "virtualmmuusagesupported": false, + "vmnpivwwndisablesupported": false, + "vmnpivwwnsupported": false, + "vmnpivwwnupdatesupported": false, + "vpmcsupported": false + }, + "config": { + "alternateguestname": "", + "annotation": null, + "bootoptions": null, + "changetrackingenabled": null, + "changeversion": "", + "consolepreferences": null, + "contentlibiteminfo": null, + "cpuaffinity": null, + "cpuallocation": {}, + "cpufeaturemask": [], + "cpuhotaddenabled": null, + "cpuhotremoveenabled": null, + "createdate": null, + "datastoreurl": [], + "defaultpowerops": {}, + "dynamicproperty": [], + "dynamictype": null, + "extraconfig": [], + "files": {}, + "firmware": null, + "flags": {}, + "forkconfiginfo": null, + "ftinfo": null, + "guestautolockenabled": null, + "guestfullname": "otherGuest", + "guestid": "otherGuest", + "guestintegrityinfo": null, + "guestmonitoringmodeinfo": null, + "hardware": {}, + "hotplugmemoryincrementsize": null, + "hotplugmemorylimit": null, + "initialoverhead": null, + "instanceuuid": "12f8928d-f144-5c57-89db-dd2d0902c9fa", + "keyid": null, + "latencysensitivity": null, + "locationid": null, + "managedby": null, + "maxmksconnections": null, + "memoryaffinity": null, + "memoryallocation": {}, + "memoryhotaddenabled": null, + "memoryreservationlockedtomax": null, + "messagebustunnelenabled": null, + "migrateencryption": null, + "modified": {}, + "name": "DC0_H0_VM1", + "nestedhvenabled": null, + "networkshaper": null, + "npivdesirednodewwns": null, + "npivdesiredportwwns": null, + "npivnodeworldwidename": [], + "npivonnonrdmdisks": null, + "npivportworldwidename": [], + "npivtemporarydisabled": null, + "npivworldwidenametype": null, + "repconfig": null, + "scheduledhardwareupgradeinfo": null, + "sgxinfo": null, + "swapplacement": null, + "swapstorageobjectid": null, + "template": false, + "tools": {}, + "uuid": "39365506-5a0a-5fd0-be10-9586ad53aaad", + "vappconfig": null, + "vassertsenabled": null, + "vcpuconfig": [], + "version": "vmx-13", + "vflashcachereservation": null, + "vmstorageobjectid": null, + "vmxconfigchecksum": null, + "vpmcenabled": null + }, + "configissue": [], + "configstatus": "green", + "customvalue": [], + "datastore": [ + { + "_moId": "/tmp/govcsim-DC0-LocalDS_0-949174843@folder-5", + "name": "LocalDS_0" + } + ], + "effectiverole": [ + -1 + ], + "guest": { + "appheartbeatstatus": null, + "appstate": null, + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "generationinfo": [], + "guestfamily": null, + "guestfullname": null, + "guestid": null, + "guestkernelcrashed": null, + "guestoperationsready": null, + "gueststate": "", + "gueststatechangesupported": null, + "hostname": null, + "hwversion": null, + "interactiveguestoperationsready": null, + "ipaddress": null, + "ipstack": [], + "net": [], + "screen": null, + "toolsinstalltype": null, + "toolsrunningstatus": "guestToolsNotRunning", + "toolsstatus": "toolsNotInstalled", + "toolsversion": "0", + "toolsversionstatus": null, + "toolsversionstatus2": null + }, + "guestheartbeatstatus": null, + "layout": { + "configfile": [], + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "logfile": [], + "snapshot": [], + "swapfile": null + }, + "layoutex": { + "disk": [], + "dynamicproperty": [], + "dynamictype": null, + "file": [], + "snapshot": [], + "timestamp": {} + }, + "name": "DC0_H0_VM1", + "network": [], + "overallstatus": "green", + "parentvapp": null, + "permission": [], + "recenttask": [], + "resourcepool": { + "_moId": "resgroup-22", + "name": "Resources" + }, + "rootsnapshot": [], + "runtime": { + "boottime": null, + "cleanpoweroff": null, + "connectionstate": "connected", + "consolidationneeded": false, + "cryptostate": null, + "dasvmprotection": null, + "device": [], + "dynamicproperty": [], + "dynamictype": null, + "faulttolerancestate": null, + "featuremask": [], + "featurerequirement": [], + "host": { + "_moId": "host-21", + "name": "DC0_H0" + }, + "instantclonefrozen": null, + "maxcpuusage": null, + "maxmemoryusage": null, + "memoryoverhead": null, + "minrequiredevcmodekey": null, + "needsecondaryreason": null, + "nummksconnections": 0, + "offlinefeaturerequirement": [], + "onlinestandby": false, + "paused": null, + "powerstate": "poweredOn", + "question": null, + "quiescedforkparent": null, + "recordreplaystate": null, + "snapshotinbackground": null, + "suspendinterval": null, + "suspendtime": null, + "toolsinstallermounted": false, + "vflashcacheallocation": null + }, + "snapshot": null, + "storage": { + "dynamicproperty": [], + "dynamictype": null, + "perdatastoreusage": [], + "timestamp": {} + }, + "summary": { + "config": {}, + "customvalue": [], + "dynamicproperty": [], + "dynamictype": null, + "guest": {}, + "overallstatus": "green", + "quickstats": {}, + "runtime": {}, + "storage": {}, + "vm": {} + }, + "tag": [], + "triggeredalarmstate": [], + "value": [] + } + } + }, + "all": { + "children": [ + "None", + "guests", + "ungrouped" + ] + }, + "guests": { + "hosts": [ + "DC0_C0_RP0_VM0_cd0681bf-2f18-5c00-9b9b-8197c0095348", + "DC0_C0_RP0_VM1_f7c371d6-2003-5a48-9859-3bc9a8b08908", + "DC0_H0_VM0_265104de-1472-547c-b873-6dc7883fb6cb", + "DC0_H0_VM1_39365506-5a0a-5fd0-be10-9586ad53aaad" + ] + } +} diff --git a/test/integration/targets/inventory_script/inventory.sh b/test/integration/targets/inventory_script/inventory.sh new file mode 100755 index 00000000000..b3f1d0353cf --- /dev/null +++ b/test/integration/targets/inventory_script/inventory.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# This script mimics the output from what the contrib/inventory/vmware_inventory.py +# dynamic inventory script produced. +# This ensures we are still covering the same code that the original tests gave us +# and subsequently ensures that ansible-inventory produces output consistent with +# that of a dynamic inventory script +cat inventory.json diff --git a/test/integration/targets/inventory_script/runme.sh b/test/integration/targets/inventory_script/runme.sh new file mode 100755 index 00000000000..bb4fcea91af --- /dev/null +++ b/test/integration/targets/inventory_script/runme.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -eux + +diff -uw <(ansible-inventory -i inventory.sh --list --export) inventory.json diff --git a/test/integration/targets/plugin_config_for_inventory/test_inventory.py b/test/integration/targets/plugin_config_for_inventory/test_inventory.py index 009caf75a13..63ed0cc27ef 100644 --- a/test/integration/targets/plugin_config_for_inventory/test_inventory.py +++ b/test/integration/targets/plugin_config_for_inventory/test_inventory.py @@ -39,7 +39,8 @@ class InventoryModule(BaseInventoryPlugin): def parse(self, inventory, loader, path, cache=True): super(InventoryModule, self).parse(inventory, loader, path) - self._read_config_data(path=path) + config_data = self._read_config_data(path=path) + self._consume_options(config_data) departments = self.get_option('departments') diff --git a/test/support/integration/plugins/inventory/vmware_vm_inventory.py b/test/support/integration/plugins/inventory/vmware_vm_inventory.py deleted file mode 100644 index 816b6471c5d..00000000000 --- a/test/support/integration/plugins/inventory/vmware_vm_inventory.py +++ /dev/null @@ -1,477 +0,0 @@ -# -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, Abhijeet Kasurde -# -# 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 - -DOCUMENTATION = ''' - name: vmware_vm_inventory - plugin_type: inventory - short_description: VMware Guest inventory source - version_added: "2.7" - author: - - Abhijeet Kasurde (@Akasurde) - description: - - Get virtual machines as inventory hosts from VMware environment. - - Uses any file which ends with vmware.yml, vmware.yaml, vmware_vm_inventory.yml, or vmware_vm_inventory.yaml as a YAML configuration file. - - The inventory_hostname is always the 'Name' and UUID of the virtual machine. UUID is added as VMware allows virtual machines with the same name. - extends_documentation_fragment: - - inventory_cache - requirements: - - "Python >= 2.7" - - "PyVmomi" - - "requests >= 2.3" - - "vSphere Automation SDK - For tag feature" - - "vCloud Suite SDK - For tag feature" - options: - hostname: - description: Name of vCenter or ESXi server. - required: True - env: - - name: VMWARE_HOST - - name: VMWARE_SERVER - username: - description: Name of vSphere admin user. - required: True - env: - - name: VMWARE_USER - - name: VMWARE_USERNAME - password: - description: Password of vSphere admin user. - required: True - env: - - name: VMWARE_PASSWORD - port: - description: Port number used to connect to vCenter or ESXi Server. - default: 443 - env: - - name: VMWARE_PORT - validate_certs: - description: - - Allows connection when SSL certificates are not valid. Set to C(false) when certificates are not trusted. - default: True - type: boolean - env: - - name: VMWARE_VALIDATE_CERTS - with_tags: - description: - - Include tags and associated virtual machines. - - Requires 'vSphere Automation SDK' library to be installed on the given controller machine. - - Please refer following URLs for installation steps - - 'https://code.vmware.com/web/sdk/65/vsphere-automation-python' - default: False - type: boolean - properties: - description: - - Specify the list of VMware schema properties associated with the VM. - - These properties will be populated in hostvars of the given VM. - - Each value in the list specifies the path to a specific property in VM object. - type: list - default: [ 'name', 'config.cpuHotAddEnabled', 'config.cpuHotRemoveEnabled', - 'config.instanceUuid', 'config.hardware.numCPU', 'config.template', - 'config.name', 'guest.hostName', 'guest.ipAddress', - 'guest.guestId', 'guest.guestState', 'runtime.maxMemoryUsage', - 'customValue' - ] - version_added: "2.9" -''' - -EXAMPLES = ''' -# Sample configuration file for VMware Guest dynamic inventory - plugin: vmware_vm_inventory - strict: False - hostname: 10.65.223.31 - username: administrator@vsphere.local - password: Esxi@123$% - validate_certs: False - with_tags: True - -# Gather minimum set of properties for VMware guest - plugin: vmware_vm_inventory - strict: False - hostname: 10.65.223.31 - username: administrator@vsphere.local - password: Esxi@123$% - validate_certs: False - with_tags: False - properties: - - 'name' - - 'guest.ipAddress' -''' - -import ssl -import atexit -from ansible.errors import AnsibleError, AnsibleParserError - -try: - # requests is required for exception handling of the ConnectionError - import requests - HAS_REQUESTS = True -except ImportError: - HAS_REQUESTS = False - -try: - from pyVim import connect - from pyVmomi import vim, vmodl - HAS_PYVMOMI = True -except ImportError: - HAS_PYVMOMI = False - -try: - from com.vmware.vapi.std_client import DynamicID - from vmware.vapi.vsphere.client import create_vsphere_client - HAS_VSPHERE = True -except ImportError: - HAS_VSPHERE = False - - -from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable - - -class BaseVMwareInventory: - def __init__(self, hostname, username, password, port, validate_certs, with_tags): - self.hostname = hostname - self.username = username - self.password = password - self.port = port - self.with_tags = with_tags - self.validate_certs = validate_certs - self.content = None - self.rest_content = None - - def do_login(self): - """ - Check requirements and do login - """ - self.check_requirements() - self.content = self._login() - if self.with_tags: - self.rest_content = self._login_vapi() - - def _login_vapi(self): - """ - Login to vCenter API using REST call - Returns: connection object - - """ - session = requests.Session() - session.verify = self.validate_certs - if not self.validate_certs: - # Disable warning shown at stdout - requests.packages.urllib3.disable_warnings() - - server = self.hostname - if self.port: - server += ":" + str(self.port) - client = create_vsphere_client(server=server, - username=self.username, - password=self.password, - session=session) - if client is None: - raise AnsibleError("Failed to login to %s using %s" % (server, self.username)) - return client - - def _login(self): - """ - Login to vCenter or ESXi server - Returns: connection object - - """ - if self.validate_certs and not hasattr(ssl, 'SSLContext'): - raise AnsibleError('pyVim does not support changing verification mode with python < 2.7.9. Either update ' - 'python or set validate_certs to false in configuration YAML file.') - - ssl_context = None - if not self.validate_certs and hasattr(ssl, 'SSLContext'): - ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - ssl_context.verify_mode = ssl.CERT_NONE - - service_instance = None - try: - service_instance = connect.SmartConnect(host=self.hostname, user=self.username, - pwd=self.password, sslContext=ssl_context, - port=self.port) - except vim.fault.InvalidLogin as e: - raise AnsibleParserError("Unable to log on to vCenter or ESXi API at %s:%s as %s: %s" % (self.hostname, self.port, self.username, e.msg)) - except vim.fault.NoPermission as e: - raise AnsibleParserError("User %s does not have required permission" - " to log on to vCenter or ESXi API at %s:%s : %s" % (self.username, self.hostname, self.port, e.msg)) - except (requests.ConnectionError, ssl.SSLError) as e: - raise AnsibleParserError("Unable to connect to vCenter or ESXi API at %s on TCP/%s: %s" % (self.hostname, self.port, e)) - except vmodl.fault.InvalidRequest as e: - # Request is malformed - raise AnsibleParserError("Failed to get a response from server %s:%s as " - "request is malformed: %s" % (self.hostname, self.port, e.msg)) - except Exception as e: - raise AnsibleParserError("Unknown error while connecting to vCenter or ESXi API at %s:%s : %s" % (self.hostname, self.port, e)) - - if service_instance is None: - raise AnsibleParserError("Unknown error while connecting to vCenter or ESXi API at %s:%s" % (self.hostname, self.port)) - - atexit.register(connect.Disconnect, service_instance) - return service_instance.RetrieveContent() - - def check_requirements(self): - """ Check all requirements for this inventory are satisified""" - if not HAS_REQUESTS: - raise AnsibleParserError('Please install "requests" Python module as this is required' - ' for VMware Guest dynamic inventory plugin.') - elif not HAS_PYVMOMI: - raise AnsibleParserError('Please install "PyVmomi" Python module as this is required' - ' for VMware Guest dynamic inventory plugin.') - if HAS_REQUESTS: - # Pyvmomi 5.5 and onwards requires requests 2.3 - # https://github.com/vmware/pyvmomi/blob/master/requirements.txt - required_version = (2, 3) - requests_version = requests.__version__.split(".")[:2] - try: - requests_major_minor = tuple(map(int, requests_version)) - except ValueError: - raise AnsibleParserError("Failed to parse 'requests' library version.") - - if requests_major_minor < required_version: - raise AnsibleParserError("'requests' library version should" - " be >= %s, found: %s." % (".".join([str(w) for w in required_version]), - requests.__version__)) - - if not HAS_VSPHERE and self.with_tags: - raise AnsibleError("Unable to find 'vSphere Automation SDK' Python library which is required." - " Please refer this URL for installation steps" - " - https://code.vmware.com/web/sdk/65/vsphere-automation-python") - - if not all([self.hostname, self.username, self.password]): - raise AnsibleError("Missing one of the following : hostname, username, password. Please read " - "the documentation for more information.") - - def _get_managed_objects_properties(self, vim_type, properties=None): - """ - Look up a Managed Object Reference in vCenter / ESXi Environment - :param vim_type: Type of vim object e.g, for datacenter - vim.Datacenter - :param properties: List of properties related to vim object e.g. Name - :return: local content object - """ - # Get Root Folder - root_folder = self.content.rootFolder - - if properties is None: - properties = ['name'] - - # Create Container View with default root folder - mor = self.content.viewManager.CreateContainerView(root_folder, [vim_type], True) - - # Create Traversal spec - traversal_spec = vmodl.query.PropertyCollector.TraversalSpec( - name="traversal_spec", - path='view', - skip=False, - type=vim.view.ContainerView - ) - - # Create Property Spec - property_spec = vmodl.query.PropertyCollector.PropertySpec( - type=vim_type, # Type of object to retrieved - all=False, - pathSet=properties - ) - - # Create Object Spec - object_spec = vmodl.query.PropertyCollector.ObjectSpec( - obj=mor, - skip=True, - selectSet=[traversal_spec] - ) - - # Create Filter Spec - filter_spec = vmodl.query.PropertyCollector.FilterSpec( - objectSet=[object_spec], - propSet=[property_spec], - reportMissingObjectsInResults=False - ) - - return self.content.propertyCollector.RetrieveContents([filter_spec]) - - @staticmethod - def _get_object_prop(vm, attributes): - """Safely get a property or return None""" - result = vm - for attribute in attributes: - try: - result = getattr(result, attribute) - except (AttributeError, IndexError): - return None - return result - - -class InventoryModule(BaseInventoryPlugin, Cacheable): - - NAME = 'vmware_vm_inventory' - - def verify_file(self, path): - """ - Verify plugin configuration file and mark this plugin active - Args: - path: Path of configuration YAML file - Returns: True if everything is correct, else False - """ - valid = False - if super(InventoryModule, self).verify_file(path): - if path.endswith(('vmware.yaml', 'vmware.yml', 'vmware_vm_inventory.yaml', 'vmware_vm_inventory.yml')): - valid = True - - return valid - - def parse(self, inventory, loader, path, cache=True): - """ - Parses the inventory file - """ - super(InventoryModule, self).parse(inventory, loader, path, cache=cache) - - cache_key = self.get_cache_key(path) - - config_data = self._read_config_data(path) - - # set _options from config data - self._consume_options(config_data) - - self.pyv = BaseVMwareInventory( - hostname=self.get_option('hostname'), - username=self.get_option('username'), - password=self.get_option('password'), - port=self.get_option('port'), - with_tags=self.get_option('with_tags'), - validate_certs=self.get_option('validate_certs') - ) - - self.pyv.do_login() - - self.pyv.check_requirements() - - source_data = None - if cache: - cache = self.get_option('cache') - - update_cache = False - if cache: - try: - source_data = self._cache[cache_key] - except KeyError: - update_cache = True - - using_current_cache = cache and not update_cache - cacheable_results = self._populate_from_source(source_data, using_current_cache) - - if update_cache: - self._cache[cache_key] = cacheable_results - - def _populate_from_cache(self, source_data): - """ Populate cache using source data """ - hostvars = source_data.pop('_meta', {}).get('hostvars', {}) - for group in source_data: - if group == 'all': - continue - else: - self.inventory.add_group(group) - hosts = source_data[group].get('hosts', []) - for host in hosts: - self._populate_host_vars([host], hostvars.get(host, {}), group) - self.inventory.add_child('all', group) - - def _populate_from_source(self, source_data, using_current_cache): - """ - Populate inventory data from direct source - - """ - if using_current_cache: - self._populate_from_cache(source_data) - return source_data - - cacheable_results = {'_meta': {'hostvars': {}}} - hostvars = {} - objects = self.pyv._get_managed_objects_properties(vim_type=vim.VirtualMachine, - properties=['name']) - - if self.pyv.with_tags: - tag_svc = self.pyv.rest_content.tagging.Tag - tag_association = self.pyv.rest_content.tagging.TagAssociation - - tags_info = dict() - tags = tag_svc.list() - for tag in tags: - tag_obj = tag_svc.get(tag) - tags_info[tag_obj.id] = tag_obj.name - if tag_obj.name not in cacheable_results: - cacheable_results[tag_obj.name] = {'hosts': []} - self.inventory.add_group(tag_obj.name) - - for vm_obj in objects: - for vm_obj_property in vm_obj.propSet: - # VMware does not provide a way to uniquely identify VM by its name - # i.e. there can be two virtual machines with same name - # Appending "_" and VMware UUID to make it unique - if not vm_obj.obj.config: - # Sometime orphaned VMs return no configurations - continue - - current_host = vm_obj_property.val + "_" + vm_obj.obj.config.uuid - - if current_host not in hostvars: - hostvars[current_host] = {} - self.inventory.add_host(current_host) - - host_ip = vm_obj.obj.guest.ipAddress - if host_ip: - self.inventory.set_variable(current_host, 'ansible_host', host_ip) - - self._populate_host_properties(vm_obj, current_host) - - # Only gather facts related to tag if vCloud and vSphere is installed. - if HAS_VSPHERE and self.pyv.with_tags: - # Add virtual machine to appropriate tag group - vm_mo_id = vm_obj.obj._GetMoId() - vm_dynamic_id = DynamicID(type='VirtualMachine', id=vm_mo_id) - attached_tags = tag_association.list_attached_tags(vm_dynamic_id) - - for tag_id in attached_tags: - self.inventory.add_child(tags_info[tag_id], current_host) - cacheable_results[tags_info[tag_id]]['hosts'].append(current_host) - - # Based on power state of virtual machine - vm_power = str(vm_obj.obj.summary.runtime.powerState) - if vm_power not in cacheable_results: - cacheable_results[vm_power] = {'hosts': []} - self.inventory.add_group(vm_power) - cacheable_results[vm_power]['hosts'].append(current_host) - self.inventory.add_child(vm_power, current_host) - - # Based on guest id - vm_guest_id = vm_obj.obj.config.guestId - if vm_guest_id and vm_guest_id not in cacheable_results: - cacheable_results[vm_guest_id] = {'hosts': []} - self.inventory.add_group(vm_guest_id) - cacheable_results[vm_guest_id]['hosts'].append(current_host) - self.inventory.add_child(vm_guest_id, current_host) - - for host in hostvars: - h = self.inventory.get_host(host) - cacheable_results['_meta']['hostvars'][h.name] = h.vars - - return cacheable_results - - def _populate_host_properties(self, vm_obj, current_host): - # Load VM properties in host_vars - vm_properties = self.get_option('properties') or [] - - field_mgr = self.pyv.content.customFieldsManager.field - - for vm_prop in vm_properties: - if vm_prop == 'customValue': - for cust_value in vm_obj.obj.customValue: - self.inventory.set_variable(current_host, - [y.name for y in field_mgr if y.key == cust_value.key][0], - cust_value.value) - else: - vm_value = self.pyv._get_object_prop(vm_obj.obj, vm_prop.split(".")) - self.inventory.set_variable(current_host, vm_prop, vm_value) diff --git a/test/support/integration/plugins/module_utils/vmware.py b/test/support/integration/plugins/module_utils/vmware.py deleted file mode 100644 index 765e8c18f21..00000000000 --- a/test/support/integration/plugins/module_utils/vmware.py +++ /dev/null @@ -1,1630 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright: (c) 2015, Joseph Callen -# Copyright: (c) 2018, Ansible Project -# Copyright: (c) 2018, James E. King III (@jeking3) -# 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 - -import atexit -import ansible.module_utils.common._collections_compat as collections_compat -import json -import os -import re -import ssl -import time -import traceback -from random import randint -from distutils.version import StrictVersion - -REQUESTS_IMP_ERR = None -try: - # requests is required for exception handling of the ConnectionError - import requests - HAS_REQUESTS = True -except ImportError: - REQUESTS_IMP_ERR = traceback.format_exc() - HAS_REQUESTS = False - -PYVMOMI_IMP_ERR = None -try: - from pyVim import connect - from pyVmomi import vim, vmodl, VmomiSupport - HAS_PYVMOMI = True - HAS_PYVMOMIJSON = hasattr(VmomiSupport, 'VmomiJSONEncoder') -except ImportError: - PYVMOMI_IMP_ERR = traceback.format_exc() - HAS_PYVMOMI = False - HAS_PYVMOMIJSON = False - -from ansible.module_utils._text import to_text, to_native -from ansible.module_utils.six import integer_types, iteritems, string_types, raise_from -from ansible.module_utils.basic import env_fallback, missing_required_lib - - -class TaskError(Exception): - def __init__(self, *args, **kwargs): - super(TaskError, self).__init__(*args, **kwargs) - - -def wait_for_task(task, max_backoff=64, timeout=3600): - """Wait for given task using exponential back-off algorithm. - - Args: - task: VMware task object - max_backoff: Maximum amount of sleep time in seconds - timeout: Timeout for the given task in seconds - - Returns: Tuple with True and result for successful task - Raises: TaskError on failure - """ - failure_counter = 0 - start_time = time.time() - - while True: - if time.time() - start_time >= timeout: - raise TaskError("Timeout") - if task.info.state == vim.TaskInfo.State.success: - return True, task.info.result - if task.info.state == vim.TaskInfo.State.error: - error_msg = task.info.error - host_thumbprint = None - try: - error_msg = error_msg.msg - if hasattr(task.info.error, 'thumbprint'): - host_thumbprint = task.info.error.thumbprint - except AttributeError: - pass - finally: - raise_from(TaskError(error_msg, host_thumbprint), task.info.error) - if task.info.state in [vim.TaskInfo.State.running, vim.TaskInfo.State.queued]: - sleep_time = min(2 ** failure_counter + randint(1, 1000) / 1000, max_backoff) - time.sleep(sleep_time) - failure_counter += 1 - - -def wait_for_vm_ip(content, vm, timeout=300): - facts = dict() - interval = 15 - while timeout > 0: - _facts = gather_vm_facts(content, vm) - if _facts['ipv4'] or _facts['ipv6']: - facts = _facts - break - time.sleep(interval) - timeout -= interval - - return facts - - -def find_obj(content, vimtype, name, first=True, folder=None): - container = content.viewManager.CreateContainerView(folder or content.rootFolder, recursive=True, type=vimtype) - # Get all objects matching type (and name if given) - obj_list = [obj for obj in container.view if not name or to_text(obj.name) == to_text(name)] - container.Destroy() - - # Return first match or None - if first: - if obj_list: - return obj_list[0] - return None - - # Return all matching objects or empty list - return obj_list - - -def find_dvspg_by_name(dv_switch, portgroup_name): - portgroup_name = quote_obj_name(portgroup_name) - portgroups = dv_switch.portgroup - - for pg in portgroups: - if pg.name == portgroup_name: - return pg - - return None - - -def find_object_by_name(content, name, obj_type, folder=None, recurse=True): - if not isinstance(obj_type, list): - obj_type = [obj_type] - - objects = get_all_objs(content, obj_type, folder=folder, recurse=recurse) - for obj in objects: - if obj.name == name: - return obj - - return None - - -def find_cluster_by_name(content, cluster_name, datacenter=None): - - if datacenter and hasattr(datacenter, 'hostFolder'): - folder = datacenter.hostFolder - else: - folder = content.rootFolder - - return find_object_by_name(content, cluster_name, [vim.ClusterComputeResource], folder=folder) - - -def find_datacenter_by_name(content, datacenter_name): - return find_object_by_name(content, datacenter_name, [vim.Datacenter]) - - -def get_parent_datacenter(obj): - """ Walk the parent tree to find the objects datacenter """ - if isinstance(obj, vim.Datacenter): - return obj - datacenter = None - while True: - if not hasattr(obj, 'parent'): - break - obj = obj.parent - if isinstance(obj, vim.Datacenter): - datacenter = obj - break - return datacenter - - -def find_datastore_by_name(content, datastore_name, datacenter_name=None): - return find_object_by_name(content, datastore_name, [vim.Datastore], datacenter_name) - - -def find_folder_by_name(content, folder_name): - return find_object_by_name(content, folder_name, [vim.Folder]) - - -def find_dvs_by_name(content, switch_name, folder=None): - return find_object_by_name(content, switch_name, [vim.DistributedVirtualSwitch], folder=folder) - - -def find_hostsystem_by_name(content, hostname): - return find_object_by_name(content, hostname, [vim.HostSystem]) - - -def find_resource_pool_by_name(content, resource_pool_name): - return find_object_by_name(content, resource_pool_name, [vim.ResourcePool]) - - -def find_resource_pool_by_cluster(content, resource_pool_name='Resources', cluster=None): - return find_object_by_name(content, resource_pool_name, [vim.ResourcePool], folder=cluster) - - -def find_network_by_name(content, network_name): - return find_object_by_name(content, quote_obj_name(network_name), [vim.Network]) - - -def find_vm_by_id(content, vm_id, vm_id_type="vm_name", datacenter=None, - cluster=None, folder=None, match_first=False): - """ UUID is unique to a VM, every other id returns the first match. """ - si = content.searchIndex - vm = None - - if vm_id_type == 'dns_name': - vm = si.FindByDnsName(datacenter=datacenter, dnsName=vm_id, vmSearch=True) - elif vm_id_type == 'uuid': - # Search By BIOS UUID rather than instance UUID - vm = si.FindByUuid(datacenter=datacenter, instanceUuid=False, uuid=vm_id, vmSearch=True) - elif vm_id_type == 'instance_uuid': - vm = si.FindByUuid(datacenter=datacenter, instanceUuid=True, uuid=vm_id, vmSearch=True) - elif vm_id_type == 'ip': - vm = si.FindByIp(datacenter=datacenter, ip=vm_id, vmSearch=True) - elif vm_id_type == 'vm_name': - folder = None - if cluster: - folder = cluster - elif datacenter: - folder = datacenter.hostFolder - vm = find_vm_by_name(content, vm_id, folder) - elif vm_id_type == 'inventory_path': - searchpath = folder - # get all objects for this path - f_obj = si.FindByInventoryPath(searchpath) - if f_obj: - if isinstance(f_obj, vim.Datacenter): - f_obj = f_obj.vmFolder - for c_obj in f_obj.childEntity: - if not isinstance(c_obj, vim.VirtualMachine): - continue - if c_obj.name == vm_id: - vm = c_obj - if match_first: - break - return vm - - -def find_vm_by_name(content, vm_name, folder=None, recurse=True): - return find_object_by_name(content, vm_name, [vim.VirtualMachine], folder=folder, recurse=recurse) - - -def find_host_portgroup_by_name(host, portgroup_name): - - for portgroup in host.config.network.portgroup: - if portgroup.spec.name == portgroup_name: - return portgroup - return None - - -def compile_folder_path_for_object(vobj): - """ make a /vm/foo/bar/baz like folder path for an object """ - - paths = [] - if isinstance(vobj, vim.Folder): - paths.append(vobj.name) - - thisobj = vobj - while hasattr(thisobj, 'parent'): - thisobj = thisobj.parent - try: - moid = thisobj._moId - except AttributeError: - moid = None - if moid in ['group-d1', 'ha-folder-root']: - break - if isinstance(thisobj, vim.Folder): - paths.append(thisobj.name) - paths.reverse() - return '/' + '/'.join(paths) - - -def _get_vm_prop(vm, attributes): - """Safely get a property or return None""" - result = vm - for attribute in attributes: - try: - result = getattr(result, attribute) - except (AttributeError, IndexError): - return None - return result - - -def gather_vm_facts(content, vm): - """ Gather facts from vim.VirtualMachine object. """ - facts = { - 'module_hw': True, - 'hw_name': vm.config.name, - 'hw_power_status': vm.summary.runtime.powerState, - 'hw_guest_full_name': vm.summary.guest.guestFullName, - 'hw_guest_id': vm.summary.guest.guestId, - 'hw_product_uuid': vm.config.uuid, - 'hw_processor_count': vm.config.hardware.numCPU, - 'hw_cores_per_socket': vm.config.hardware.numCoresPerSocket, - 'hw_memtotal_mb': vm.config.hardware.memoryMB, - 'hw_interfaces': [], - 'hw_datastores': [], - 'hw_files': [], - 'hw_esxi_host': None, - 'hw_guest_ha_state': None, - 'hw_is_template': vm.config.template, - 'hw_folder': None, - 'hw_version': vm.config.version, - 'instance_uuid': vm.config.instanceUuid, - 'guest_tools_status': _get_vm_prop(vm, ('guest', 'toolsRunningStatus')), - 'guest_tools_version': _get_vm_prop(vm, ('guest', 'toolsVersion')), - 'guest_question': vm.summary.runtime.question, - 'guest_consolidation_needed': vm.summary.runtime.consolidationNeeded, - 'ipv4': None, - 'ipv6': None, - 'annotation': vm.config.annotation, - 'customvalues': {}, - 'snapshots': [], - 'current_snapshot': None, - 'vnc': {}, - 'moid': vm._moId, - 'vimref': "vim.VirtualMachine:%s" % vm._moId, - } - - # facts that may or may not exist - if vm.summary.runtime.host: - try: - host = vm.summary.runtime.host - facts['hw_esxi_host'] = host.summary.config.name - facts['hw_cluster'] = host.parent.name if host.parent and isinstance(host.parent, vim.ClusterComputeResource) else None - - except vim.fault.NoPermission: - # User does not have read permission for the host system, - # proceed without this value. This value does not contribute or hamper - # provisioning or power management operations. - pass - if vm.summary.runtime.dasVmProtection: - facts['hw_guest_ha_state'] = vm.summary.runtime.dasVmProtection.dasProtected - - datastores = vm.datastore - for ds in datastores: - facts['hw_datastores'].append(ds.info.name) - - try: - files = vm.config.files - layout = vm.layout - if files: - facts['hw_files'] = [files.vmPathName] - for item in layout.snapshot: - for snap in item.snapshotFile: - if 'vmsn' in snap: - facts['hw_files'].append(snap) - for item in layout.configFile: - facts['hw_files'].append(os.path.join(os.path.dirname(files.vmPathName), item)) - for item in vm.layout.logFile: - facts['hw_files'].append(os.path.join(files.logDirectory, item)) - for item in vm.layout.disk: - for disk in item.diskFile: - facts['hw_files'].append(disk) - except Exception: - pass - - facts['hw_folder'] = PyVmomi.get_vm_path(content, vm) - - cfm = content.customFieldsManager - # Resolve custom values - for value_obj in vm.summary.customValue: - kn = value_obj.key - if cfm is not None and cfm.field: - for f in cfm.field: - if f.key == value_obj.key: - kn = f.name - # Exit the loop immediately, we found it - break - - facts['customvalues'][kn] = value_obj.value - - net_dict = {} - vmnet = _get_vm_prop(vm, ('guest', 'net')) - if vmnet: - for device in vmnet: - if device.deviceConfigId > 0: - net_dict[device.macAddress] = list(device.ipAddress) - - if vm.guest.ipAddress: - if ':' in vm.guest.ipAddress: - facts['ipv6'] = vm.guest.ipAddress - else: - facts['ipv4'] = vm.guest.ipAddress - - ethernet_idx = 0 - for entry in vm.config.hardware.device: - if not hasattr(entry, 'macAddress'): - continue - - if entry.macAddress: - mac_addr = entry.macAddress - mac_addr_dash = mac_addr.replace(':', '-') - else: - mac_addr = mac_addr_dash = None - - if (hasattr(entry, 'backing') and hasattr(entry.backing, 'port') and - hasattr(entry.backing.port, 'portKey') and hasattr(entry.backing.port, 'portgroupKey')): - port_group_key = entry.backing.port.portgroupKey - port_key = entry.backing.port.portKey - else: - port_group_key = None - port_key = None - - factname = 'hw_eth' + str(ethernet_idx) - facts[factname] = { - 'addresstype': entry.addressType, - 'label': entry.deviceInfo.label, - 'macaddress': mac_addr, - 'ipaddresses': net_dict.get(entry.macAddress, None), - 'macaddress_dash': mac_addr_dash, - 'summary': entry.deviceInfo.summary, - 'portgroup_portkey': port_key, - 'portgroup_key': port_group_key, - } - facts['hw_interfaces'].append('eth' + str(ethernet_idx)) - ethernet_idx += 1 - - snapshot_facts = list_snapshots(vm) - if 'snapshots' in snapshot_facts: - facts['snapshots'] = snapshot_facts['snapshots'] - facts['current_snapshot'] = snapshot_facts['current_snapshot'] - - facts['vnc'] = get_vnc_extraconfig(vm) - return facts - - -def deserialize_snapshot_obj(obj): - return {'id': obj.id, - 'name': obj.name, - 'description': obj.description, - 'creation_time': obj.createTime, - 'state': obj.state} - - -def list_snapshots_recursively(snapshots): - snapshot_data = [] - for snapshot in snapshots: - snapshot_data.append(deserialize_snapshot_obj(snapshot)) - snapshot_data = snapshot_data + list_snapshots_recursively(snapshot.childSnapshotList) - return snapshot_data - - -def get_current_snap_obj(snapshots, snapob): - snap_obj = [] - for snapshot in snapshots: - if snapshot.snapshot == snapob: - snap_obj.append(snapshot) - snap_obj = snap_obj + get_current_snap_obj(snapshot.childSnapshotList, snapob) - return snap_obj - - -def list_snapshots(vm): - result = {} - snapshot = _get_vm_prop(vm, ('snapshot',)) - if not snapshot: - return result - if vm.snapshot is None: - return result - - result['snapshots'] = list_snapshots_recursively(vm.snapshot.rootSnapshotList) - current_snapref = vm.snapshot.currentSnapshot - current_snap_obj = get_current_snap_obj(vm.snapshot.rootSnapshotList, current_snapref) - if current_snap_obj: - result['current_snapshot'] = deserialize_snapshot_obj(current_snap_obj[0]) - else: - result['current_snapshot'] = dict() - return result - - -def get_vnc_extraconfig(vm): - result = {} - for opts in vm.config.extraConfig: - for optkeyname in ['enabled', 'ip', 'port', 'password']: - if opts.key.lower() == "remotedisplay.vnc." + optkeyname: - result[optkeyname] = opts.value - return result - - -def vmware_argument_spec(): - return dict( - hostname=dict(type='str', - required=False, - fallback=(env_fallback, ['VMWARE_HOST']), - ), - username=dict(type='str', - aliases=['user', 'admin'], - required=False, - fallback=(env_fallback, ['VMWARE_USER'])), - password=dict(type='str', - aliases=['pass', 'pwd'], - required=False, - no_log=True, - fallback=(env_fallback, ['VMWARE_PASSWORD'])), - port=dict(type='int', - default=443, - fallback=(env_fallback, ['VMWARE_PORT'])), - validate_certs=dict(type='bool', - required=False, - default=True, - fallback=(env_fallback, ['VMWARE_VALIDATE_CERTS']) - ), - proxy_host=dict(type='str', - required=False, - default=None, - fallback=(env_fallback, ['VMWARE_PROXY_HOST'])), - proxy_port=dict(type='int', - required=False, - default=None, - fallback=(env_fallback, ['VMWARE_PROXY_PORT'])), - ) - - -def connect_to_api(module, disconnect_atexit=True, return_si=False, hostname=None, username=None, password=None, port=None, validate_certs=None): - hostname = hostname if hostname else module.params['hostname'] - username = username if username else module.params['username'] - password = password if password else module.params['password'] - port = port if port else module.params.get('port', 443) - validate_certs = validate_certs if validate_certs else module.params['validate_certs'] - - if not hostname: - module.fail_json(msg="Hostname parameter is missing." - " Please specify this parameter in task or" - " export environment variable like 'export VMWARE_HOST=ESXI_HOSTNAME'") - - if not username: - module.fail_json(msg="Username parameter is missing." - " Please specify this parameter in task or" - " export environment variable like 'export VMWARE_USER=ESXI_USERNAME'") - - if not password: - module.fail_json(msg="Password parameter is missing." - " Please specify this parameter in task or" - " export environment variable like 'export VMWARE_PASSWORD=ESXI_PASSWORD'") - - if validate_certs and not hasattr(ssl, 'SSLContext'): - module.fail_json(msg='pyVim does not support changing verification mode with python < 2.7.9. Either update ' - 'python or use validate_certs=false.') - elif validate_certs: - ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - ssl_context.verify_mode = ssl.CERT_REQUIRED - ssl_context.check_hostname = True - ssl_context.load_default_certs() - elif hasattr(ssl, 'SSLContext'): - ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - ssl_context.verify_mode = ssl.CERT_NONE - ssl_context.check_hostname = False - else: # Python < 2.7.9 or RHEL/Centos < 7.4 - ssl_context = None - - service_instance = None - proxy_host = module.params.get('proxy_host') - proxy_port = module.params.get('proxy_port') - - connect_args = dict( - host=hostname, - port=port, - ) - if ssl_context: - connect_args.update(sslContext=ssl_context) - - msg_suffix = '' - try: - if proxy_host: - msg_suffix = " [proxy: %s:%d]" % (proxy_host, proxy_port) - connect_args.update(httpProxyHost=proxy_host, httpProxyPort=proxy_port) - smart_stub = connect.SmartStubAdapter(**connect_args) - session_stub = connect.VimSessionOrientedStub(smart_stub, connect.VimSessionOrientedStub.makeUserLoginMethod(username, password)) - service_instance = vim.ServiceInstance('ServiceInstance', session_stub) - else: - connect_args.update(user=username, pwd=password) - service_instance = connect.SmartConnect(**connect_args) - except vim.fault.InvalidLogin as invalid_login: - msg = "Unable to log on to vCenter or ESXi API at %s:%s " % (hostname, port) - module.fail_json(msg="%s as %s: %s" % (msg, username, invalid_login.msg) + msg_suffix) - except vim.fault.NoPermission as no_permission: - module.fail_json(msg="User %s does not have required permission" - " to log on to vCenter or ESXi API at %s:%s : %s" % (username, hostname, port, no_permission.msg)) - except (requests.ConnectionError, ssl.SSLError) as generic_req_exc: - module.fail_json(msg="Unable to connect to vCenter or ESXi API at %s on TCP/%s: %s" % (hostname, port, generic_req_exc)) - except vmodl.fault.InvalidRequest as invalid_request: - # Request is malformed - msg = "Failed to get a response from server %s:%s " % (hostname, port) - module.fail_json(msg="%s as request is malformed: %s" % (msg, invalid_request.msg) + msg_suffix) - except Exception as generic_exc: - msg = "Unknown error while connecting to vCenter or ESXi API at %s:%s" % (hostname, port) + msg_suffix - module.fail_json(msg="%s : %s" % (msg, generic_exc)) - - if service_instance is None: - msg = "Unknown error while connecting to vCenter or ESXi API at %s:%s" % (hostname, port) - module.fail_json(msg=msg + msg_suffix) - - # Disabling atexit should be used in special cases only. - # Such as IP change of the ESXi host which removes the connection anyway. - # Also removal significantly speeds up the return of the module - if disconnect_atexit: - atexit.register(connect.Disconnect, service_instance) - if return_si: - return service_instance, service_instance.RetrieveContent() - return service_instance.RetrieveContent() - - -def get_all_objs(content, vimtype, folder=None, recurse=True): - if not folder: - folder = content.rootFolder - - obj = {} - container = content.viewManager.CreateContainerView(folder, vimtype, recurse) - for managed_object_ref in container.view: - obj.update({managed_object_ref: managed_object_ref.name}) - return obj - - -def run_command_in_guest(content, vm, username, password, program_path, program_args, program_cwd, program_env): - - result = {'failed': False} - - tools_status = vm.guest.toolsStatus - if (tools_status == 'toolsNotInstalled' or - tools_status == 'toolsNotRunning'): - result['failed'] = True - result['msg'] = "VMwareTools is not installed or is not running in the guest" - return result - - # https://github.com/vmware/pyvmomi/blob/master/docs/vim/vm/guest/NamePasswordAuthentication.rst - creds = vim.vm.guest.NamePasswordAuthentication( - username=username, password=password - ) - - try: - # https://github.com/vmware/pyvmomi/blob/master/docs/vim/vm/guest/ProcessManager.rst - pm = content.guestOperationsManager.processManager - # https://www.vmware.com/support/developer/converter-sdk/conv51_apireference/vim.vm.guest.ProcessManager.ProgramSpec.html - ps = vim.vm.guest.ProcessManager.ProgramSpec( - # programPath=program, - # arguments=args - programPath=program_path, - arguments=program_args, - workingDirectory=program_cwd, - ) - - res = pm.StartProgramInGuest(vm, creds, ps) - result['pid'] = res - pdata = pm.ListProcessesInGuest(vm, creds, [res]) - - # wait for pid to finish - while not pdata[0].endTime: - time.sleep(1) - pdata = pm.ListProcessesInGuest(vm, creds, [res]) - - result['owner'] = pdata[0].owner - result['startTime'] = pdata[0].startTime.isoformat() - result['endTime'] = pdata[0].endTime.isoformat() - result['exitCode'] = pdata[0].exitCode - if result['exitCode'] != 0: - result['failed'] = True - result['msg'] = "program exited non-zero" - else: - result['msg'] = "program completed successfully" - - except Exception as e: - result['msg'] = str(e) - result['failed'] = True - - return result - - -def serialize_spec(clonespec): - """Serialize a clonespec or a relocation spec""" - data = {} - attrs = dir(clonespec) - attrs = [x for x in attrs if not x.startswith('_')] - for x in attrs: - xo = getattr(clonespec, x) - if callable(xo): - continue - xt = type(xo) - if xo is None: - data[x] = None - elif isinstance(xo, vim.vm.ConfigSpec): - data[x] = serialize_spec(xo) - elif isinstance(xo, vim.vm.RelocateSpec): - data[x] = serialize_spec(xo) - elif isinstance(xo, vim.vm.device.VirtualDisk): - data[x] = serialize_spec(xo) - elif isinstance(xo, vim.vm.device.VirtualDeviceSpec.FileOperation): - data[x] = to_text(xo) - elif isinstance(xo, vim.Description): - data[x] = { - 'dynamicProperty': serialize_spec(xo.dynamicProperty), - 'dynamicType': serialize_spec(xo.dynamicType), - 'label': serialize_spec(xo.label), - 'summary': serialize_spec(xo.summary), - } - elif hasattr(xo, 'name'): - data[x] = to_text(xo) + ':' + to_text(xo.name) - elif isinstance(xo, vim.vm.ProfileSpec): - pass - elif issubclass(xt, list): - data[x] = [] - for xe in xo: - data[x].append(serialize_spec(xe)) - elif issubclass(xt, string_types + integer_types + (float, bool)): - if issubclass(xt, integer_types): - data[x] = int(xo) - else: - data[x] = to_text(xo) - elif issubclass(xt, bool): - data[x] = xo - elif issubclass(xt, dict): - data[to_text(x)] = {} - for k, v in xo.items(): - k = to_text(k) - data[x][k] = serialize_spec(v) - else: - data[x] = str(xt) - - return data - - -def find_host_by_cluster_datacenter(module, content, datacenter_name, cluster_name, host_name): - dc = find_datacenter_by_name(content, datacenter_name) - if dc is None: - module.fail_json(msg="Unable to find datacenter with name %s" % datacenter_name) - cluster = find_cluster_by_name(content, cluster_name, datacenter=dc) - if cluster is None: - module.fail_json(msg="Unable to find cluster with name %s" % cluster_name) - - for host in cluster.host: - if host.name == host_name: - return host, cluster - - return None, cluster - - -def set_vm_power_state(content, vm, state, force, timeout=0): - """ - Set the power status for a VM determined by the current and - requested states. force is forceful - """ - facts = gather_vm_facts(content, vm) - expected_state = state.replace('_', '').replace('-', '').lower() - current_state = facts['hw_power_status'].lower() - result = dict( - changed=False, - failed=False, - ) - - # Need Force - if not force and current_state not in ['poweredon', 'poweredoff']: - result['failed'] = True - result['msg'] = "Virtual Machine is in %s power state. Force is required!" % current_state - result['instance'] = gather_vm_facts(content, vm) - return result - - # State is not already true - if current_state != expected_state: - task = None - try: - if expected_state == 'poweredoff': - task = vm.PowerOff() - - elif expected_state == 'poweredon': - task = vm.PowerOn() - - elif expected_state == 'restarted': - if current_state in ('poweredon', 'poweringon', 'resetting', 'poweredoff'): - task = vm.Reset() - else: - result['failed'] = True - result['msg'] = "Cannot restart virtual machine in the current state %s" % current_state - - elif expected_state == 'suspended': - if current_state in ('poweredon', 'poweringon'): - task = vm.Suspend() - else: - result['failed'] = True - result['msg'] = 'Cannot suspend virtual machine in the current state %s' % current_state - - elif expected_state in ['shutdownguest', 'rebootguest']: - if current_state == 'poweredon': - if vm.guest.toolsRunningStatus == 'guestToolsRunning': - if expected_state == 'shutdownguest': - task = vm.ShutdownGuest() - if timeout > 0: - result.update(wait_for_poweroff(vm, timeout)) - else: - task = vm.RebootGuest() - # Set result['changed'] immediately because - # shutdown and reboot return None. - result['changed'] = True - else: - result['failed'] = True - result['msg'] = "VMware tools should be installed for guest shutdown/reboot" - else: - result['failed'] = True - result['msg'] = "Virtual machine %s must be in poweredon state for guest shutdown/reboot" % vm.name - - else: - result['failed'] = True - result['msg'] = "Unsupported expected state provided: %s" % expected_state - - except Exception as e: - result['failed'] = True - result['msg'] = to_text(e) - - if task: - wait_for_task(task) - if task.info.state == 'error': - result['failed'] = True - result['msg'] = task.info.error.msg - else: - result['changed'] = True - - # need to get new metadata if changed - result['instance'] = gather_vm_facts(content, vm) - - return result - - -def wait_for_poweroff(vm, timeout=300): - result = dict() - interval = 15 - while timeout > 0: - if vm.runtime.powerState.lower() == 'poweredoff': - break - time.sleep(interval) - timeout -= interval - else: - result['failed'] = True - result['msg'] = 'Timeout while waiting for VM power off.' - return result - - -def is_integer(value, type_of='int'): - try: - VmomiSupport.vmodlTypes[type_of](value) - return True - except (TypeError, ValueError): - return False - - -def is_boolean(value): - if str(value).lower() in ['true', 'on', 'yes', 'false', 'off', 'no']: - return True - return False - - -def is_truthy(value): - if str(value).lower() in ['true', 'on', 'yes']: - return True - return False - - -# options is the dict as defined in the module parameters, current_options is -# the list of the currently set options as returned by the vSphere API. -def option_diff(options, current_options): - current_options_dict = {} - for option in current_options: - current_options_dict[option.key] = option.value - - change_option_list = [] - for option_key, option_value in options.items(): - if is_boolean(option_value): - option_value = VmomiSupport.vmodlTypes['bool'](is_truthy(option_value)) - elif isinstance(option_value, int): - option_value = VmomiSupport.vmodlTypes['int'](option_value) - elif isinstance(option_value, float): - option_value = VmomiSupport.vmodlTypes['float'](option_value) - elif isinstance(option_value, str): - option_value = VmomiSupport.vmodlTypes['string'](option_value) - - if option_key not in current_options_dict or current_options_dict[option_key] != option_value: - change_option_list.append(vim.option.OptionValue(key=option_key, value=option_value)) - - return change_option_list - - -def quote_obj_name(object_name=None): - """ - Replace special characters in object name - with urllib quote equivalent - - """ - if not object_name: - return None - - from collections import OrderedDict - SPECIAL_CHARS = OrderedDict({ - '%': '%25', - '/': '%2f', - '\\': '%5c' - }) - for key in SPECIAL_CHARS.keys(): - if key in object_name: - object_name = object_name.replace(key, SPECIAL_CHARS[key]) - - return object_name - - -class PyVmomi(object): - def __init__(self, module): - """ - Constructor - """ - if not HAS_REQUESTS: - module.fail_json(msg=missing_required_lib('requests'), - exception=REQUESTS_IMP_ERR) - - if not HAS_PYVMOMI: - module.fail_json(msg=missing_required_lib('PyVmomi'), - exception=PYVMOMI_IMP_ERR) - - self.module = module - self.params = module.params - self.current_vm_obj = None - self.si, self.content = connect_to_api(self.module, return_si=True) - self.custom_field_mgr = [] - if self.content.customFieldsManager: # not an ESXi - self.custom_field_mgr = self.content.customFieldsManager.field - - def is_vcenter(self): - """ - Check if given hostname is vCenter or ESXi host - Returns: True if given connection is with vCenter server - False if given connection is with ESXi server - - """ - api_type = None - try: - api_type = self.content.about.apiType - except (vmodl.RuntimeFault, vim.fault.VimFault) as exc: - self.module.fail_json(msg="Failed to get status of vCenter server : %s" % exc.msg) - - if api_type == 'VirtualCenter': - return True - elif api_type == 'HostAgent': - return False - - def get_managed_objects_properties(self, vim_type, properties=None): - """ - Look up a Managed Object Reference in vCenter / ESXi Environment - :param vim_type: Type of vim object e.g, for datacenter - vim.Datacenter - :param properties: List of properties related to vim object e.g. Name - :return: local content object - """ - # Get Root Folder - root_folder = self.content.rootFolder - - if properties is None: - properties = ['name'] - - # Create Container View with default root folder - mor = self.content.viewManager.CreateContainerView(root_folder, [vim_type], True) - - # Create Traversal spec - traversal_spec = vmodl.query.PropertyCollector.TraversalSpec( - name="traversal_spec", - path='view', - skip=False, - type=vim.view.ContainerView - ) - - # Create Property Spec - property_spec = vmodl.query.PropertyCollector.PropertySpec( - type=vim_type, # Type of object to retrieved - all=False, - pathSet=properties - ) - - # Create Object Spec - object_spec = vmodl.query.PropertyCollector.ObjectSpec( - obj=mor, - skip=True, - selectSet=[traversal_spec] - ) - - # Create Filter Spec - filter_spec = vmodl.query.PropertyCollector.FilterSpec( - objectSet=[object_spec], - propSet=[property_spec], - reportMissingObjectsInResults=False - ) - - return self.content.propertyCollector.RetrieveContents([filter_spec]) - - # Virtual Machine related functions - def get_vm(self): - """ - Find unique virtual machine either by UUID, MoID or Name. - Returns: virtual machine object if found, else None. - - """ - vm_obj = None - user_desired_path = None - use_instance_uuid = self.params.get('use_instance_uuid') or False - if 'uuid' in self.params and self.params['uuid']: - if not use_instance_uuid: - vm_obj = find_vm_by_id(self.content, vm_id=self.params['uuid'], vm_id_type="uuid") - elif use_instance_uuid: - vm_obj = find_vm_by_id(self.content, - vm_id=self.params['uuid'], - vm_id_type="instance_uuid") - elif 'name' in self.params and self.params['name']: - objects = self.get_managed_objects_properties(vim_type=vim.VirtualMachine, properties=['name']) - vms = [] - - for temp_vm_object in objects: - if ( - len(temp_vm_object.propSet) == 1 and - temp_vm_object.propSet[0].val == self.params['name']): - vms.append(temp_vm_object.obj) - - # get_managed_objects_properties may return multiple virtual machine, - # following code tries to find user desired one depending upon the folder specified. - if len(vms) > 1: - # We have found multiple virtual machines, decide depending upon folder value - if self.params['folder'] is None: - self.module.fail_json(msg="Multiple virtual machines with same name [%s] found, " - "Folder value is a required parameter to find uniqueness " - "of the virtual machine" % self.params['name'], - details="Please see documentation of the vmware_guest module " - "for folder parameter.") - - # Get folder path where virtual machine is located - # User provided folder where user thinks virtual machine is present - user_folder = self.params['folder'] - # User defined datacenter - user_defined_dc = self.params['datacenter'] - # User defined datacenter's object - datacenter_obj = find_datacenter_by_name(self.content, self.params['datacenter']) - # Get Path for Datacenter - dcpath = compile_folder_path_for_object(vobj=datacenter_obj) - - # Nested folder does not return trailing / - if not dcpath.endswith('/'): - dcpath += '/' - - if user_folder in [None, '', '/']: - # User provided blank value or - # User provided only root value, we fail - self.module.fail_json(msg="vmware_guest found multiple virtual machines with same " - "name [%s], please specify folder path other than blank " - "or '/'" % self.params['name']) - elif user_folder.startswith('/vm/'): - # User provided nested folder under VMware default vm folder i.e. folder = /vm/india/finance - user_desired_path = "%s%s%s" % (dcpath, user_defined_dc, user_folder) - else: - # User defined datacenter is not nested i.e. dcpath = '/' , or - # User defined datacenter is nested i.e. dcpath = '/F0/DC0' or - # User provided folder starts with / and datacenter i.e. folder = /ha-datacenter/ or - # User defined folder starts with datacenter without '/' i.e. - # folder = DC0/vm/india/finance or - # folder = DC0/vm - user_desired_path = user_folder - - for vm in vms: - # Check if user has provided same path as virtual machine - actual_vm_folder_path = self.get_vm_path(content=self.content, vm_name=vm) - if not actual_vm_folder_path.startswith("%s%s" % (dcpath, user_defined_dc)): - continue - if user_desired_path in actual_vm_folder_path: - vm_obj = vm - break - elif vms: - # Unique virtual machine found. - actual_vm_folder_path = self.get_vm_path(content=self.content, vm_name=vms[0]) - if self.params.get('folder') is None: - vm_obj = vms[0] - elif self.params['folder'] in actual_vm_folder_path: - vm_obj = vms[0] - elif 'moid' in self.params and self.params['moid']: - vm_obj = VmomiSupport.templateOf('VirtualMachine')(self.params['moid'], self.si._stub) - - if vm_obj: - self.current_vm_obj = vm_obj - - return vm_obj - - def gather_facts(self, vm): - """ - Gather facts of virtual machine. - Args: - vm: Name of virtual machine. - - Returns: Facts dictionary of the given virtual machine. - - """ - return gather_vm_facts(self.content, vm) - - @staticmethod - def get_vm_path(content, vm_name): - """ - Find the path of virtual machine. - Args: - content: VMware content object - vm_name: virtual machine managed object - - Returns: Folder of virtual machine if exists, else None - - """ - folder_name = None - folder = vm_name.parent - if folder: - folder_name = folder.name - fp = folder.parent - # climb back up the tree to find our path, stop before the root folder - while fp is not None and fp.name is not None and fp != content.rootFolder: - folder_name = fp.name + '/' + folder_name - try: - fp = fp.parent - except Exception: - break - folder_name = '/' + folder_name - return folder_name - - def get_vm_or_template(self, template_name=None): - """ - Find the virtual machine or virtual machine template using name - used for cloning purpose. - Args: - template_name: Name of virtual machine or virtual machine template - - Returns: virtual machine or virtual machine template object - - """ - template_obj = None - if not template_name: - return template_obj - - if "/" in template_name: - vm_obj_path = os.path.dirname(template_name) - vm_obj_name = os.path.basename(template_name) - template_obj = find_vm_by_id(self.content, vm_obj_name, vm_id_type="inventory_path", folder=vm_obj_path) - if template_obj: - return template_obj - else: - template_obj = find_vm_by_id(self.content, vm_id=template_name, vm_id_type="uuid") - if template_obj: - return template_obj - - objects = self.get_managed_objects_properties(vim_type=vim.VirtualMachine, properties=['name']) - templates = [] - - for temp_vm_object in objects: - if len(temp_vm_object.propSet) != 1: - continue - for temp_vm_object_property in temp_vm_object.propSet: - if temp_vm_object_property.val == template_name: - templates.append(temp_vm_object.obj) - break - - if len(templates) > 1: - # We have found multiple virtual machine templates - self.module.fail_json(msg="Multiple virtual machines or templates with same name [%s] found." % template_name) - elif templates: - template_obj = templates[0] - - return template_obj - - # Cluster related functions - def find_cluster_by_name(self, cluster_name, datacenter_name=None): - """ - Find Cluster by name in given datacenter - Args: - cluster_name: Name of cluster name to find - datacenter_name: (optional) Name of datacenter - - Returns: True if found - - """ - return find_cluster_by_name(self.content, cluster_name, datacenter=datacenter_name) - - def get_all_hosts_by_cluster(self, cluster_name): - """ - Get all hosts from cluster by cluster name - Args: - cluster_name: Name of cluster - - Returns: List of hosts - - """ - cluster_obj = self.find_cluster_by_name(cluster_name=cluster_name) - if cluster_obj: - return [host for host in cluster_obj.host] - else: - return [] - - # Hosts related functions - def find_hostsystem_by_name(self, host_name): - """ - Find Host by name - Args: - host_name: Name of ESXi host - - Returns: True if found - - """ - return find_hostsystem_by_name(self.content, hostname=host_name) - - def get_all_host_objs(self, cluster_name=None, esxi_host_name=None): - """ - Get all host system managed object - - Args: - cluster_name: Name of Cluster - esxi_host_name: Name of ESXi server - - Returns: A list of all host system managed objects, else empty list - - """ - host_obj_list = [] - if not self.is_vcenter(): - hosts = get_all_objs(self.content, [vim.HostSystem]).keys() - if hosts: - host_obj_list.append(list(hosts)[0]) - else: - if cluster_name: - cluster_obj = self.find_cluster_by_name(cluster_name=cluster_name) - if cluster_obj: - host_obj_list = [host for host in cluster_obj.host] - else: - self.module.fail_json(changed=False, msg="Cluster '%s' not found" % cluster_name) - elif esxi_host_name: - if isinstance(esxi_host_name, str): - esxi_host_name = [esxi_host_name] - - for host in esxi_host_name: - esxi_host_obj = self.find_hostsystem_by_name(host_name=host) - if esxi_host_obj: - host_obj_list.append(esxi_host_obj) - else: - self.module.fail_json(changed=False, msg="ESXi '%s' not found" % host) - - return host_obj_list - - def host_version_at_least(self, version=None, vm_obj=None, host_name=None): - """ - Check that the ESXi Host is at least a specific version number - Args: - vm_obj: virtual machine object, required one of vm_obj, host_name - host_name (string): ESXi host name - version (tuple): a version tuple, for example (6, 7, 0) - Returns: bool - """ - if vm_obj: - host_system = vm_obj.summary.runtime.host - elif host_name: - host_system = self.find_hostsystem_by_name(host_name=host_name) - else: - self.module.fail_json(msg='VM object or ESXi host name must be set one.') - if host_system and version: - host_version = host_system.summary.config.product.version - return StrictVersion(host_version) >= StrictVersion('.'.join(map(str, version))) - else: - self.module.fail_json(msg='Unable to get the ESXi host from vm: %s, or hostname %s,' - 'or the passed ESXi version: %s is None.' % (vm_obj, host_name, version)) - - # Network related functions - @staticmethod - def find_host_portgroup_by_name(host, portgroup_name): - """ - Find Portgroup on given host - Args: - host: Host config object - portgroup_name: Name of portgroup - - Returns: True if found else False - - """ - for portgroup in host.config.network.portgroup: - if portgroup.spec.name == portgroup_name: - return portgroup - return False - - def get_all_port_groups_by_host(self, host_system): - """ - Get all Port Group by host - Args: - host_system: Name of Host System - - Returns: List of Port Group Spec - """ - pgs_list = [] - for pg in host_system.config.network.portgroup: - pgs_list.append(pg) - return pgs_list - - def find_network_by_name(self, network_name=None): - """ - Get network specified by name - Args: - network_name: Name of network - - Returns: List of network managed objects - """ - networks = [] - - if not network_name: - return networks - - objects = self.get_managed_objects_properties(vim_type=vim.Network, properties=['name']) - - for temp_vm_object in objects: - if len(temp_vm_object.propSet) != 1: - continue - for temp_vm_object_property in temp_vm_object.propSet: - if temp_vm_object_property.val == network_name: - networks.append(temp_vm_object.obj) - break - return networks - - def network_exists_by_name(self, network_name=None): - """ - Check if network with a specified name exists or not - Args: - network_name: Name of network - - Returns: True if network exists else False - """ - ret = False - if not network_name: - return ret - ret = True if self.find_network_by_name(network_name=network_name) else False - return ret - - # Datacenter - def find_datacenter_by_name(self, datacenter_name): - """ - Get datacenter managed object by name - - Args: - datacenter_name: Name of datacenter - - Returns: datacenter managed object if found else None - - """ - return find_datacenter_by_name(self.content, datacenter_name=datacenter_name) - - def is_datastore_valid(self, datastore_obj=None): - """ - Check if datastore selected is valid or not - Args: - datastore_obj: datastore managed object - - Returns: True if datastore is valid, False if not - """ - if not datastore_obj \ - or datastore_obj.summary.maintenanceMode != 'normal' \ - or not datastore_obj.summary.accessible: - return False - return True - - def find_datastore_by_name(self, datastore_name, datacenter_name=None): - """ - Get datastore managed object by name - Args: - datastore_name: Name of datastore - datacenter_name: Name of datacenter where the datastore resides. This is needed because Datastores can be - shared across Datacenters, so we need to specify the datacenter to assure we get the correct Managed Object Reference - - Returns: datastore managed object if found else None - - """ - return find_datastore_by_name(self.content, datastore_name=datastore_name, datacenter_name=datacenter_name) - - def find_folder_by_name(self, folder_name): - """ - Get vm folder managed object by name - Args: - folder_name: Name of the vm folder - - Returns: vm folder managed object if found else None - - """ - return find_folder_by_name(self.content, folder_name=folder_name) - - # Datastore cluster - def find_datastore_cluster_by_name(self, datastore_cluster_name): - """ - Get datastore cluster managed object by name - Args: - datastore_cluster_name: Name of datastore cluster - - Returns: Datastore cluster managed object if found else None - - """ - data_store_clusters = get_all_objs(self.content, [vim.StoragePod]) - for dsc in data_store_clusters: - if dsc.name == datastore_cluster_name: - return dsc - return None - - # Resource pool - def find_resource_pool_by_name(self, resource_pool_name, folder=None): - """ - Get resource pool managed object by name - Args: - resource_pool_name: Name of resource pool - - Returns: Resource pool managed object if found else None - - """ - if not folder: - folder = self.content.rootFolder - - resource_pools = get_all_objs(self.content, [vim.ResourcePool], folder=folder) - for rp in resource_pools: - if rp.name == resource_pool_name: - return rp - return None - - def find_resource_pool_by_cluster(self, resource_pool_name='Resources', cluster=None): - """ - Get resource pool managed object by cluster object - Args: - resource_pool_name: Name of resource pool - cluster: Managed object of cluster - - Returns: Resource pool managed object if found else None - - """ - desired_rp = None - if not cluster: - return desired_rp - - if resource_pool_name != 'Resources': - # Resource pool name is different than default 'Resources' - resource_pools = cluster.resourcePool.resourcePool - if resource_pools: - for rp in resource_pools: - if rp.name == resource_pool_name: - desired_rp = rp - break - else: - desired_rp = cluster.resourcePool - - return desired_rp - - # VMDK stuff - def vmdk_disk_path_split(self, vmdk_path): - """ - Takes a string in the format - - [datastore_name] path/to/vm_name.vmdk - - Returns a tuple with multiple strings: - - 1. datastore_name: The name of the datastore (without brackets) - 2. vmdk_fullpath: The "path/to/vm_name.vmdk" portion - 3. vmdk_filename: The "vm_name.vmdk" portion of the string (os.path.basename equivalent) - 4. vmdk_folder: The "path/to/" portion of the string (os.path.dirname equivalent) - """ - try: - datastore_name = re.match(r'^\[(.*?)\]', vmdk_path, re.DOTALL).groups()[0] - vmdk_fullpath = re.match(r'\[.*?\] (.*)$', vmdk_path).groups()[0] - vmdk_filename = os.path.basename(vmdk_fullpath) - vmdk_folder = os.path.dirname(vmdk_fullpath) - return datastore_name, vmdk_fullpath, vmdk_filename, vmdk_folder - except (IndexError, AttributeError) as e: - self.module.fail_json(msg="Bad path '%s' for filename disk vmdk image: %s" % (vmdk_path, to_native(e))) - - def find_vmdk_file(self, datastore_obj, vmdk_fullpath, vmdk_filename, vmdk_folder): - """ - Return vSphere file object or fail_json - Args: - datastore_obj: Managed object of datastore - vmdk_fullpath: Path of VMDK file e.g., path/to/vm/vmdk_filename.vmdk - vmdk_filename: Name of vmdk e.g., VM0001_1.vmdk - vmdk_folder: Base dir of VMDK e.g, path/to/vm - - """ - - browser = datastore_obj.browser - datastore_name = datastore_obj.name - datastore_name_sq = "[" + datastore_name + "]" - if browser is None: - self.module.fail_json(msg="Unable to access browser for datastore %s" % datastore_name) - - detail_query = vim.host.DatastoreBrowser.FileInfo.Details( - fileOwner=True, - fileSize=True, - fileType=True, - modification=True - ) - search_spec = vim.host.DatastoreBrowser.SearchSpec( - details=detail_query, - matchPattern=[vmdk_filename], - searchCaseInsensitive=True, - ) - search_res = browser.SearchSubFolders( - datastorePath=datastore_name_sq, - searchSpec=search_spec - ) - - changed = False - vmdk_path = datastore_name_sq + " " + vmdk_fullpath - try: - changed, result = wait_for_task(search_res) - except TaskError as task_e: - self.module.fail_json(msg=to_native(task_e)) - - if not changed: - self.module.fail_json(msg="No valid disk vmdk image found for path %s" % vmdk_path) - - target_folder_paths = [ - datastore_name_sq + " " + vmdk_folder + '/', - datastore_name_sq + " " + vmdk_folder, - ] - - for file_result in search_res.info.result: - for f in getattr(file_result, 'file'): - if f.path == vmdk_filename and file_result.folderPath in target_folder_paths: - return f - - self.module.fail_json(msg="No vmdk file found for path specified [%s]" % vmdk_path) - - # - # Conversion to JSON - # - - def _deepmerge(self, d, u): - """ - Deep merges u into d. - - Credit: - https://bit.ly/2EDOs1B (stackoverflow question 3232943) - License: - cc-by-sa 3.0 (https://creativecommons.org/licenses/by-sa/3.0/) - Changes: - using collections_compat for compatibility - - Args: - - d (dict): dict to merge into - - u (dict): dict to merge into d - - Returns: - dict, with u merged into d - """ - for k, v in iteritems(u): - if isinstance(v, collections_compat.Mapping): - d[k] = self._deepmerge(d.get(k, {}), v) - else: - d[k] = v - return d - - def _extract(self, data, remainder): - """ - This is used to break down dotted properties for extraction. - - Args: - - data (dict): result of _jsonify on a property - - remainder: the remainder of the dotted property to select - - Return: - dict - """ - result = dict() - if '.' not in remainder: - result[remainder] = data[remainder] - return result - key, remainder = remainder.split('.', 1) - result[key] = self._extract(data[key], remainder) - return result - - def _jsonify(self, obj): - """ - Convert an object from pyVmomi into JSON. - - Args: - - obj (object): vim object - - Return: - dict - """ - return json.loads(json.dumps(obj, cls=VmomiSupport.VmomiJSONEncoder, - sort_keys=True, strip_dynamic=True)) - - def to_json(self, obj, properties=None): - """ - Convert a vSphere (pyVmomi) Object into JSON. This is a deep - transformation. The list of properties is optional - if not - provided then all properties are deeply converted. The resulting - JSON is sorted to improve human readability. - - Requires upstream support from pyVmomi > 6.7.1 - (https://github.com/vmware/pyvmomi/pull/732) - - Args: - - obj (object): vim object - - properties (list, optional): list of properties following - the property collector specification, for example: - ["config.hardware.memoryMB", "name", "overallStatus"] - default is a complete object dump, which can be large - - Return: - dict - """ - if not HAS_PYVMOMIJSON: - self.module.fail_json(msg='The installed version of pyvmomi lacks JSON output support; need pyvmomi>6.7.1') - - result = dict() - if properties: - for prop in properties: - try: - if '.' in prop: - key, remainder = prop.split('.', 1) - tmp = dict() - tmp[key] = self._extract(self._jsonify(getattr(obj, key)), remainder) - self._deepmerge(result, tmp) - else: - result[prop] = self._jsonify(getattr(obj, prop)) - # To match gather_vm_facts output - prop_name = prop - if prop.lower() == '_moid': - prop_name = 'moid' - elif prop.lower() == '_vimref': - prop_name = 'vimref' - result[prop_name] = result[prop] - except (AttributeError, KeyError): - self.module.fail_json(msg="Property '{0}' not found.".format(prop)) - else: - result = self._jsonify(obj) - return result - - def get_folder_path(self, cur): - full_path = '/' + cur.name - while hasattr(cur, 'parent') and cur.parent: - if cur.parent == self.content.rootFolder: - break - cur = cur.parent - full_path = '/' + cur.name + full_path - return full_path diff --git a/test/support/integration/plugins/modules/vmware_guest.py b/test/support/integration/plugins/modules/vmware_guest.py deleted file mode 100644 index df9f695be56..00000000000 --- a/test/support/integration/plugins/modules/vmware_guest.py +++ /dev/null @@ -1,2914 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# -# This module is also sponsored by E.T.A.I. (www.etai.fr) -# 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 = r''' ---- -module: vmware_guest -short_description: Manages virtual machines in vCenter -description: > - This module can be used to create new virtual machines from templates or other virtual machines, - manage power state of virtual machine such as power on, power off, suspend, shutdown, reboot, restart etc., - modify various virtual machine components like network, disk, customization etc., - rename a virtual machine and remove a virtual machine with associated components. -version_added: '2.2' -author: -- Loic Blot (@nerzhul) -- Philippe Dellaert (@pdellaert) -- Abhijeet Kasurde (@Akasurde) -requirements: -- python >= 2.6 -- PyVmomi -notes: - - Please make sure that the user used for M(vmware_guest) has the correct level of privileges. - - For example, following is the list of minimum privileges required by users to create virtual machines. - - " DataStore > Allocate Space" - - " Virtual Machine > Configuration > Add New Disk" - - " Virtual Machine > Configuration > Add or Remove Device" - - " Virtual Machine > Inventory > Create New" - - " Network > Assign Network" - - " Resource > Assign Virtual Machine to Resource Pool" - - "Module may require additional privileges as well, which may be required for gathering facts - e.g. ESXi configurations." - - Tested on vSphere 5.5, 6.0, 6.5 and 6.7. - - Use SCSI disks instead of IDE when you want to expand online disks by specifying a SCSI controller. - - Uses SysPrep for Windows VM (depends on 'guest_id' parameter match 'win') with PyVmomi. - - In order to change the VM's parameters (e.g. number of CPUs), the VM must be powered off unless the hot-add - support is enabled and the C(state=present) must be used to apply the changes. - - "For additional information please visit Ansible VMware community wiki - U(https://github.com/ansible/community/wiki/VMware)." -options: - state: - description: - - Specify the state the virtual machine should be in. - - 'If C(state) is set to C(present) and virtual machine exists, ensure the virtual machine - configurations conforms to task arguments.' - - 'If C(state) is set to C(absent) and virtual machine exists, then the specified virtual machine - is removed with its associated components.' - - 'If C(state) is set to one of the following C(poweredon), C(poweredoff), C(present), C(restarted), C(suspended) - and virtual machine does not exists, then virtual machine is deployed with given parameters.' - - 'If C(state) is set to C(poweredon) and virtual machine exists with powerstate other than powered on, - then the specified virtual machine is powered on.' - - 'If C(state) is set to C(poweredoff) and virtual machine exists with powerstate other than powered off, - then the specified virtual machine is powered off.' - - 'If C(state) is set to C(restarted) and virtual machine exists, then the virtual machine is restarted.' - - 'If C(state) is set to C(suspended) and virtual machine exists, then the virtual machine is set to suspended mode.' - - 'If C(state) is set to C(shutdownguest) and virtual machine exists, then the virtual machine is shutdown.' - - 'If C(state) is set to C(rebootguest) and virtual machine exists, then the virtual machine is rebooted.' - default: present - choices: [ present, absent, poweredon, poweredoff, restarted, suspended, shutdownguest, rebootguest ] - name: - description: - - Name of the virtual machine to work with. - - Virtual machine names in vCenter are not necessarily unique, which may be problematic, see C(name_match). - - 'If multiple virtual machines with same name exists, then C(folder) is required parameter to - identify uniqueness of the virtual machine.' - - This parameter is required, if C(state) is set to C(poweredon), C(poweredoff), C(present), C(restarted), C(suspended) - and virtual machine does not exists. - - This parameter is case sensitive. - required: yes - name_match: - description: - - If multiple virtual machines matching the name, use the first or last found. - default: 'first' - choices: [ first, last ] - uuid: - description: - - UUID of the virtual machine to manage if known, this is VMware's unique identifier. - - This is required if C(name) is not supplied. - - If virtual machine does not exists, then this parameter is ignored. - - Please note that a supplied UUID will be ignored on virtual machine creation, as VMware creates the UUID internally. - use_instance_uuid: - description: - - Whether to use the VMware instance UUID rather than the BIOS UUID. - default: no - type: bool - version_added: '2.8' - template: - description: - - Template or existing virtual machine used to create new virtual machine. - - If this value is not set, virtual machine is created without using a template. - - If the virtual machine already exists, this parameter will be ignored. - - This parameter is case sensitive. - - You can also specify template or VM UUID for identifying source. version_added 2.8. Use C(hw_product_uuid) from M(vmware_guest_facts) as UUID value. - - From version 2.8 onwards, absolute path to virtual machine or template can be used. - aliases: [ 'template_src' ] - is_template: - description: - - Flag the instance as a template. - - This will mark the given virtual machine as template. - default: 'no' - type: bool - version_added: '2.3' - folder: - description: - - Destination folder, absolute path to find an existing guest or create the new guest. - - The folder should include the datacenter. ESX's datacenter is ha-datacenter. - - This parameter is case sensitive. - - This parameter is required, while deploying new virtual machine. version_added 2.5. - - 'If multiple machines are found with same name, this parameter is used to identify - uniqueness of the virtual machine. version_added 2.5' - - 'Examples:' - - ' folder: /ha-datacenter/vm' - - ' folder: ha-datacenter/vm' - - ' folder: /datacenter1/vm' - - ' folder: datacenter1/vm' - - ' folder: /datacenter1/vm/folder1' - - ' folder: datacenter1/vm/folder1' - - ' folder: /folder1/datacenter1/vm' - - ' folder: folder1/datacenter1/vm' - - ' folder: /folder1/datacenter1/vm/folder2' - hardware: - description: - - Manage virtual machine's hardware attributes. - - All parameters case sensitive. - - 'Valid attributes are:' - - ' - C(hotadd_cpu) (boolean): Allow virtual CPUs to be added while the virtual machine is running.' - - ' - C(hotremove_cpu) (boolean): Allow virtual CPUs to be removed while the virtual machine is running. - version_added: 2.5' - - ' - C(hotadd_memory) (boolean): Allow memory to be added while the virtual machine is running.' - - ' - C(memory_mb) (integer): Amount of memory in MB.' - - ' - C(nested_virt) (bool): Enable nested virtualization. version_added: 2.5' - - ' - C(num_cpus) (integer): Number of CPUs.' - - ' - C(num_cpu_cores_per_socket) (integer): Number of Cores Per Socket.' - - " C(num_cpus) must be a multiple of C(num_cpu_cores_per_socket). - For example to create a VM with 2 sockets of 4 cores, specify C(num_cpus): 8 and C(num_cpu_cores_per_socket): 4" - - ' - C(scsi) (string): Valid values are C(buslogic), C(lsilogic), C(lsilogicsas) and C(paravirtual) (default).' - - " - C(memory_reservation_lock) (boolean): If set true, memory resource reservation for the virtual machine - will always be equal to the virtual machine's memory size. version_added: 2.5" - - ' - C(max_connections) (integer): Maximum number of active remote display connections for the virtual machines. - version_added: 2.5.' - - ' - C(mem_limit) (integer): The memory utilization of a virtual machine will not exceed this limit. Unit is MB. - version_added: 2.5' - - ' - C(mem_reservation) (integer): The amount of memory resource that is guaranteed available to the virtual - machine. Unit is MB. C(memory_reservation) is alias to this. version_added: 2.5' - - ' - C(cpu_limit) (integer): The CPU utilization of a virtual machine will not exceed this limit. Unit is MHz. - version_added: 2.5' - - ' - C(cpu_reservation) (integer): The amount of CPU resource that is guaranteed available to the virtual machine. - Unit is MHz. version_added: 2.5' - - ' - C(version) (integer): The Virtual machine hardware versions. Default is 10 (ESXi 5.5 and onwards). - If value specified as C(latest), version is set to the most current virtual hardware supported on the host. - C(latest) is added in version 2.10. - Please check VMware documentation for correct virtual machine hardware version. - Incorrect hardware version may lead to failure in deployment. If hardware version is already equal to the given - version then no action is taken. version_added: 2.6' - - ' - C(boot_firmware) (string): Choose which firmware should be used to boot the virtual machine. - Allowed values are "bios" and "efi". version_added: 2.7' - - ' - C(virt_based_security) (bool): Enable Virtualization Based Security feature for Windows 10. - (Support from Virtual machine hardware version 14, Guest OS Windows 10 64 bit, Windows Server 2016)' - - guest_id: - description: - - Set the guest ID. - - This parameter is case sensitive. - - 'Examples:' - - " virtual machine with RHEL7 64 bit, will be 'rhel7_64Guest'" - - " virtual machine with CentOS 64 bit, will be 'centos64Guest'" - - " virtual machine with Ubuntu 64 bit, will be 'ubuntu64Guest'" - - This field is required when creating a virtual machine, not required when creating from the template. - - > - Valid values are referenced here: - U(https://code.vmware.com/apis/358/doc/vim.vm.GuestOsDescriptor.GuestOsIdentifier.html) - version_added: '2.3' - disk: - description: - - A list of disks to add. - - This parameter is case sensitive. - - Shrinking disks is not supported. - - Removing existing disks of the virtual machine is not supported. - - 'Valid attributes are:' - - ' - C(size_[tb,gb,mb,kb]) (integer): Disk storage size in specified unit.' - - ' - C(type) (string): Valid values are:' - - ' - C(thin) thin disk' - - ' - C(eagerzeroedthick) eagerzeroedthick disk, added in version 2.5' - - ' Default: C(None) thick disk, no eagerzero.' - - ' - C(datastore) (string): The name of datastore which will be used for the disk. If C(autoselect_datastore) is set to True, - then will select the less used datastore whose name contains this "disk.datastore" string.' - - ' - C(filename) (string): Existing disk image to be used. Filename must already exist on the datastore.' - - ' Specify filename string in C([datastore_name] path/to/file.vmdk) format. Added in version 2.8.' - - ' - C(autoselect_datastore) (bool): select the less used datastore. "disk.datastore" and "disk.autoselect_datastore" - will not be used if C(datastore) is specified outside this C(disk) configuration.' - - ' - C(disk_mode) (string): Type of disk mode. Added in version 2.6' - - ' - Available options are :' - - ' - C(persistent): Changes are immediately and permanently written to the virtual disk. This is default.' - - ' - C(independent_persistent): Same as persistent, but not affected by snapshots.' - - ' - C(independent_nonpersistent): Changes to virtual disk are made to a redo log and discarded at power off, but not affected by snapshots.' - cdrom: - description: - - A CD-ROM configuration for the virtual machine. - - Or a list of CD-ROMs configuration for the virtual machine. Added in version 2.9. - - 'Parameters C(controller_type), C(controller_number), C(unit_number), C(state) are added for a list of CD-ROMs - configuration support.' - - 'Valid attributes are:' - - ' - C(type) (string): The type of CD-ROM, valid options are C(none), C(client) or C(iso). With C(none) the CD-ROM - will be disconnected but present.' - - ' - C(iso_path) (string): The datastore path to the ISO file to use, in the form of C([datastore1] path/to/file.iso). - Required if type is set C(iso).' - - ' - C(controller_type) (string): Default value is C(ide). Only C(ide) controller type for CD-ROM is supported for - now, will add SATA controller type in the future.' - - ' - C(controller_number) (int): For C(ide) controller, valid value is 0 or 1.' - - ' - C(unit_number) (int): For CD-ROM device attach to C(ide) controller, valid value is 0 or 1. - C(controller_number) and C(unit_number) are mandatory attributes.' - - ' - C(state) (string): Valid value is C(present) or C(absent). Default is C(present). If set to C(absent), then - the specified CD-ROM will be removed. For C(ide) controller, hot-add or hot-remove CD-ROM is not supported.' - version_added: '2.5' - resource_pool: - description: - - Use the given resource pool for virtual machine operation. - - This parameter is case sensitive. - - Resource pool should be child of the selected host parent. - version_added: '2.3' - wait_for_ip_address: - description: - - Wait until vCenter detects an IP address for the virtual machine. - - This requires vmware-tools (vmtoolsd) to properly work after creation. - - "vmware-tools needs to be installed on the given virtual machine in order to work with this parameter." - default: 'no' - type: bool - wait_for_ip_address_timeout: - description: - - Define a timeout (in seconds) for the wait_for_ip_address parameter. - default: '300' - type: int - version_added: '2.10' - wait_for_customization_timeout: - description: - - Define a timeout (in seconds) for the wait_for_customization parameter. - - Be careful when setting this value since the time guest customization took may differ among guest OSes. - default: '3600' - type: int - version_added: '2.10' - wait_for_customization: - description: - - Wait until vCenter detects all guest customizations as successfully completed. - - When enabled, the VM will automatically be powered on. - - "If vCenter does not detect guest customization start or succeed, failed events after time - C(wait_for_customization_timeout) parameter specified, warning message will be printed and task result is fail." - default: 'no' - type: bool - version_added: '2.8' - state_change_timeout: - description: - - If the C(state) is set to C(shutdownguest), by default the module will return immediately after sending the shutdown signal. - - If this argument is set to a positive integer, the module will instead wait for the virtual machine to reach the poweredoff state. - - The value sets a timeout in seconds for the module to wait for the state change. - default: 0 - version_added: '2.6' - snapshot_src: - description: - - Name of the existing snapshot to use to create a clone of a virtual machine. - - This parameter is case sensitive. - - While creating linked clone using C(linked_clone) parameter, this parameter is required. - version_added: '2.4' - linked_clone: - description: - - Whether to create a linked clone from the snapshot specified. - - If specified, then C(snapshot_src) is required parameter. - default: 'no' - type: bool - version_added: '2.4' - force: - description: - - Ignore warnings and complete the actions. - - This parameter is useful while removing virtual machine which is powered on state. - - 'This module reflects the VMware vCenter API and UI workflow, as such, in some cases the `force` flag will - be mandatory to perform the action to ensure you are certain the action has to be taken, no matter what the consequence. - This is specifically the case for removing a powered on the virtual machine when C(state) is set to C(absent).' - default: 'no' - type: bool - delete_from_inventory: - description: - - Whether to delete Virtual machine from inventory or delete from disk. - default: False - type: bool - version_added: '2.10' - datacenter: - description: - - Destination datacenter for the deploy operation. - - This parameter is case sensitive. - default: ha-datacenter - cluster: - description: - - The cluster name where the virtual machine will run. - - This is a required parameter, if C(esxi_hostname) is not set. - - C(esxi_hostname) and C(cluster) are mutually exclusive parameters. - - This parameter is case sensitive. - version_added: '2.3' - esxi_hostname: - description: - - The ESXi hostname where the virtual machine will run. - - This is a required parameter, if C(cluster) is not set. - - C(esxi_hostname) and C(cluster) are mutually exclusive parameters. - - This parameter is case sensitive. - annotation: - description: - - A note or annotation to include in the virtual machine. - version_added: '2.3' - customvalues: - description: - - Define a list of custom values to set on virtual machine. - - A custom value object takes two fields C(key) and C(value). - - Incorrect key and values will be ignored. - version_added: '2.3' - networks: - description: - - A list of networks (in the order of the NICs). - - Removing NICs is not allowed, while reconfiguring the virtual machine. - - All parameters and VMware object names are case sensitive. - - 'One of the below parameters is required per entry:' - - ' - C(name) (string): Name of the portgroup or distributed virtual portgroup for this interface. - When specifying distributed virtual portgroup make sure given C(esxi_hostname) or C(cluster) is associated with it.' - - ' - C(vlan) (integer): VLAN number for this interface.' - - 'Optional parameters per entry (used for virtual hardware):' - - ' - C(device_type) (string): Virtual network device (one of C(e1000), C(e1000e), C(pcnet32), C(vmxnet2), C(vmxnet3) (default), C(sriov)).' - - ' - C(mac) (string): Customize MAC address.' - - ' - C(dvswitch_name) (string): Name of the distributed vSwitch. - This value is required if multiple distributed portgroups exists with the same name. version_added 2.7' - - ' - C(start_connected) (bool): Indicates that virtual network adapter starts with associated virtual machine powers on. version_added: 2.5' - - 'Optional parameters per entry (used for OS customization):' - - ' - C(type) (string): Type of IP assignment (either C(dhcp) or C(static)). C(dhcp) is default.' - - ' - C(ip) (string): Static IP address (implies C(type: static)).' - - ' - C(netmask) (string): Static netmask required for C(ip).' - - ' - C(gateway) (string): Static gateway.' - - ' - C(dns_servers) (string): DNS servers for this network interface (Windows).' - - ' - C(domain) (string): Domain name for this network interface (Windows).' - - ' - C(wake_on_lan) (bool): Indicates if wake-on-LAN is enabled on this virtual network adapter. version_added: 2.5' - - ' - C(allow_guest_control) (bool): Enables guest control over whether the connectable device is connected. version_added: 2.5' - version_added: '2.3' - customization: - description: - - Parameters for OS customization when cloning from the template or the virtual machine, or apply to the existing virtual machine directly. - - Not all operating systems are supported for customization with respective vCenter version, - please check VMware documentation for respective OS customization. - - For supported customization operating system matrix, (see U(http://partnerweb.vmware.com/programs/guestOS/guest-os-customization-matrix.pdf)) - - All parameters and VMware object names are case sensitive. - - Linux based OSes requires Perl package to be installed for OS customizations. - - 'Common parameters (Linux/Windows):' - - ' - C(existing_vm) (bool): If set to C(True), do OS customization on the specified virtual machine directly. - If set to C(False) or not specified, do OS customization when cloning from the template or the virtual machine. version_added: 2.8' - - ' - C(dns_servers) (list): List of DNS servers to configure.' - - ' - C(dns_suffix) (list): List of domain suffixes, also known as DNS search path (default: C(domain) parameter).' - - ' - C(domain) (string): DNS domain name to use.' - - ' - C(hostname) (string): Computer hostname (default: shorted C(name) parameter). Allowed characters are alphanumeric (uppercase and lowercase) - and minus, rest of the characters are dropped as per RFC 952.' - - 'Parameters related to Linux customization:' - - ' - C(timezone) (string): Timezone (See List of supported time zones for different vSphere versions in Linux/Unix - systems (2145518) U(https://kb.vmware.com/s/article/2145518)). version_added: 2.9' - - ' - C(hwclockUTC) (bool): Specifies whether the hardware clock is in UTC or local time. - True when the hardware clock is in UTC, False when the hardware clock is in local time. version_added: 2.9' - - 'Parameters related to Windows customization:' - - ' - C(autologon) (bool): Auto logon after virtual machine customization (default: False).' - - ' - C(autologoncount) (int): Number of autologon after reboot (default: 1).' - - ' - C(domainadmin) (string): User used to join in AD domain (mandatory with C(joindomain)).' - - ' - C(domainadminpassword) (string): Password used to join in AD domain (mandatory with C(joindomain)).' - - ' - C(fullname) (string): Server owner name (default: Administrator).' - - ' - C(joindomain) (string): AD domain to join (Not compatible with C(joinworkgroup)).' - - ' - C(joinworkgroup) (string): Workgroup to join (Not compatible with C(joindomain), default: WORKGROUP).' - - ' - C(orgname) (string): Organisation name (default: ACME).' - - ' - C(password) (string): Local administrator password.' - - ' - C(productid) (string): Product ID.' - - ' - C(runonce) (list): List of commands to run at first user logon.' - - ' - C(timezone) (int): Timezone (See U(https://msdn.microsoft.com/en-us/library/ms912391.aspx)).' - version_added: '2.3' - vapp_properties: - description: - - A list of vApp properties. - - 'For full list of attributes and types refer to:' - - 'U(https://vdc-download.vmware.com/vmwb-repository/dcr-public/6b586ed2-655c-49d9-9029-bc416323cb22/ - fa0b429a-a695-4c11-b7d2-2cbc284049dc/doc/vim.vApp.PropertyInfo.html)' - - 'Basic attributes are:' - - ' - C(id) (string): Property id - required.' - - ' - C(value) (string): Property value.' - - ' - C(type) (string): Value type, string type by default.' - - ' - C(operation): C(remove): This attribute is required only when removing properties.' - version_added: '2.6' - customization_spec: - description: - - Unique name identifying the requested customization specification. - - This parameter is case sensitive. - - If set, then overrides C(customization) parameter values. - version_added: '2.6' - datastore: - description: - - Specify datastore or datastore cluster to provision virtual machine. - - 'This parameter takes precedence over "disk.datastore" parameter.' - - 'This parameter can be used to override datastore or datastore cluster setting of the virtual machine when deployed - from the template.' - - Please see example for more usage. - version_added: '2.7' - convert: - description: - - Specify convert disk type while cloning template or virtual machine. - choices: [ thin, thick, eagerzeroedthick ] - version_added: '2.8' -extends_documentation_fragment: vmware.documentation -''' - -EXAMPLES = r''' -- name: Create a virtual machine on given ESXi hostname - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - folder: /DC1/vm/ - name: test_vm_0001 - state: poweredon - guest_id: centos64Guest - # This is hostname of particular ESXi server on which user wants VM to be deployed - esxi_hostname: "{{ esxi_hostname }}" - disk: - - size_gb: 10 - type: thin - datastore: datastore1 - hardware: - memory_mb: 512 - num_cpus: 4 - scsi: paravirtual - networks: - - name: VM Network - mac: aa:bb:dd:aa:00:14 - ip: 10.10.10.100 - netmask: 255.255.255.0 - device_type: vmxnet3 - wait_for_ip_address: yes - wait_for_ip_address_timeout: 600 - delegate_to: localhost - register: deploy_vm - -- name: Create a virtual machine from a template - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - folder: /testvms - name: testvm_2 - state: poweredon - template: template_el7 - disk: - - size_gb: 10 - type: thin - datastore: g73_datastore - # Add another disk from an existing VMDK - - filename: "[datastore1] testvms/testvm_2_1/testvm_2_1.vmdk" - hardware: - memory_mb: 512 - num_cpus: 6 - num_cpu_cores_per_socket: 3 - scsi: paravirtual - memory_reservation_lock: True - mem_limit: 8096 - mem_reservation: 4096 - cpu_limit: 8096 - cpu_reservation: 4096 - max_connections: 5 - hotadd_cpu: True - hotremove_cpu: True - hotadd_memory: False - version: 12 # Hardware version of virtual machine - boot_firmware: "efi" - cdrom: - type: iso - iso_path: "[datastore1] livecd.iso" - networks: - - name: VM Network - mac: aa:bb:dd:aa:00:14 - wait_for_ip_address: yes - delegate_to: localhost - register: deploy - -- name: Clone a virtual machine from Windows template and customize - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: datacenter1 - cluster: cluster - name: testvm-2 - template: template_windows - networks: - - name: VM Network - ip: 192.168.1.100 - netmask: 255.255.255.0 - gateway: 192.168.1.1 - mac: aa:bb:dd:aa:00:14 - domain: my_domain - dns_servers: - - 192.168.1.1 - - 192.168.1.2 - - vlan: 1234 - type: dhcp - customization: - autologon: yes - dns_servers: - - 192.168.1.1 - - 192.168.1.2 - domain: my_domain - password: new_vm_password - runonce: - - powershell.exe -ExecutionPolicy Unrestricted -File C:\Windows\Temp\ConfigureRemotingForAnsible.ps1 -ForceNewSSLCert -EnableCredSSP - delegate_to: localhost - -- name: Clone a virtual machine from Linux template and customize - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - datacenter: "{{ datacenter }}" - state: present - folder: /DC1/vm - template: "{{ template }}" - name: "{{ vm_name }}" - cluster: DC1_C1 - networks: - - name: VM Network - ip: 192.168.10.11 - netmask: 255.255.255.0 - wait_for_ip_address: True - customization: - domain: "{{ guest_domain }}" - dns_servers: - - 8.9.9.9 - - 7.8.8.9 - dns_suffix: - - example.com - - example2.com - delegate_to: localhost - -- name: Rename a virtual machine (requires the virtual machine's uuid) - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - uuid: "{{ vm_uuid }}" - name: new_name - state: present - delegate_to: localhost - -- name: Remove a virtual machine by uuid - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - uuid: "{{ vm_uuid }}" - state: absent - delegate_to: localhost - -- name: Remove a virtual machine from inventory - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - name: vm_name - delete_from_inventory: True - state: absent - delegate_to: localhost - -- name: Manipulate vApp properties - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - name: vm_name - state: present - vapp_properties: - - id: remoteIP - category: Backup - label: Backup server IP - type: string - value: 10.10.10.1 - - id: old_property - operation: remove - delegate_to: localhost - -- name: Set powerstate of a virtual machine to poweroff by using UUID - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - validate_certs: no - uuid: "{{ vm_uuid }}" - state: poweredoff - delegate_to: localhost - -- name: Deploy a virtual machine in a datastore different from the datastore of the template - vmware_guest: - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - name: "{{ vm_name }}" - state: present - template: "{{ template_name }}" - # Here datastore can be different which holds template - datastore: "{{ virtual_machine_datastore }}" - hardware: - memory_mb: 512 - num_cpus: 2 - scsi: paravirtual - delegate_to: localhost - -- name: Create a diskless VM - vmware_guest: - validate_certs: False - hostname: "{{ vcenter_hostname }}" - username: "{{ vcenter_username }}" - password: "{{ vcenter_password }}" - datacenter: "{{ dc1 }}" - state: poweredoff - cluster: "{{ ccr1 }}" - name: diskless_vm - folder: /Asia-Datacenter1/vm - guest_id: centos64Guest - datastore: "{{ ds1 }}" - hardware: - memory_mb: 1024 - num_cpus: 2 - num_cpu_cores_per_socket: 1 -''' - -RETURN = r''' -instance: - description: metadata about the new virtual machine - returned: always - type: dict - sample: None -''' - -import re -import time -import string - -HAS_PYVMOMI = False -try: - from pyVmomi import vim, vmodl, VmomiSupport - HAS_PYVMOMI = True -except ImportError: - pass - -from random import randint -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.common.network import is_mac -from ansible.module_utils._text import to_text, to_native -from ansible.module_utils.vmware import (find_obj, gather_vm_facts, get_all_objs, - compile_folder_path_for_object, serialize_spec, - vmware_argument_spec, set_vm_power_state, PyVmomi, - find_dvs_by_name, find_dvspg_by_name, wait_for_vm_ip, - wait_for_task, TaskError, quote_obj_name) - - -def list_or_dict(value): - if isinstance(value, list) or isinstance(value, dict): - return value - else: - raise ValueError("'%s' is not valid, valid type is 'list' or 'dict'." % value) - - -class PyVmomiDeviceHelper(object): - """ This class is a helper to create easily VMware Objects for PyVmomiHelper """ - - def __init__(self, module): - self.module = module - self.next_disk_unit_number = 0 - self.scsi_device_type = { - 'lsilogic': vim.vm.device.VirtualLsiLogicController, - 'paravirtual': vim.vm.device.ParaVirtualSCSIController, - 'buslogic': vim.vm.device.VirtualBusLogicController, - 'lsilogicsas': vim.vm.device.VirtualLsiLogicSASController, - } - - def create_scsi_controller(self, scsi_type): - scsi_ctl = vim.vm.device.VirtualDeviceSpec() - scsi_ctl.operation = vim.vm.device.VirtualDeviceSpec.Operation.add - scsi_device = self.scsi_device_type.get(scsi_type, vim.vm.device.ParaVirtualSCSIController) - scsi_ctl.device = scsi_device() - scsi_ctl.device.busNumber = 0 - # While creating a new SCSI controller, temporary key value - # should be unique negative integers - scsi_ctl.device.key = -randint(1000, 9999) - scsi_ctl.device.hotAddRemove = True - scsi_ctl.device.sharedBus = 'noSharing' - scsi_ctl.device.scsiCtlrUnitNumber = 7 - - return scsi_ctl - - def is_scsi_controller(self, device): - return isinstance(device, tuple(self.scsi_device_type.values())) - - @staticmethod - def create_ide_controller(bus_number=0): - ide_ctl = vim.vm.device.VirtualDeviceSpec() - ide_ctl.operation = vim.vm.device.VirtualDeviceSpec.Operation.add - ide_ctl.device = vim.vm.device.VirtualIDEController() - ide_ctl.device.deviceInfo = vim.Description() - # While creating a new IDE controller, temporary key value - # should be unique negative integers - ide_ctl.device.key = -randint(200, 299) - ide_ctl.device.busNumber = bus_number - - return ide_ctl - - @staticmethod - def create_cdrom(ide_device, cdrom_type, iso_path=None, unit_number=0): - cdrom_spec = vim.vm.device.VirtualDeviceSpec() - cdrom_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add - cdrom_spec.device = vim.vm.device.VirtualCdrom() - cdrom_spec.device.controllerKey = ide_device.key - cdrom_spec.device.key = -randint(3000, 3999) - cdrom_spec.device.unitNumber = unit_number - cdrom_spec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo() - cdrom_spec.device.connectable.allowGuestControl = True - cdrom_spec.device.connectable.startConnected = (cdrom_type != "none") - if cdrom_type in ["none", "client"]: - cdrom_spec.device.backing = vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo() - elif cdrom_type == "iso": - cdrom_spec.device.backing = vim.vm.device.VirtualCdrom.IsoBackingInfo(fileName=iso_path) - - return cdrom_spec - - @staticmethod - def is_equal_cdrom(vm_obj, cdrom_device, cdrom_type, iso_path): - if cdrom_type == "none": - return (isinstance(cdrom_device.backing, vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo) and - cdrom_device.connectable.allowGuestControl and - not cdrom_device.connectable.startConnected and - (vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOn or not cdrom_device.connectable.connected)) - elif cdrom_type == "client": - return (isinstance(cdrom_device.backing, vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo) and - cdrom_device.connectable.allowGuestControl and - cdrom_device.connectable.startConnected and - (vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOn or cdrom_device.connectable.connected)) - elif cdrom_type == "iso": - return (isinstance(cdrom_device.backing, vim.vm.device.VirtualCdrom.IsoBackingInfo) and - cdrom_device.backing.fileName == iso_path and - cdrom_device.connectable.allowGuestControl and - cdrom_device.connectable.startConnected and - (vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOn or cdrom_device.connectable.connected)) - - @staticmethod - def update_cdrom_config(vm_obj, cdrom_spec, cdrom_device, iso_path=None): - # Updating an existing CD-ROM - if cdrom_spec["type"] in ["client", "none"]: - cdrom_device.backing = vim.vm.device.VirtualCdrom.RemotePassthroughBackingInfo() - elif cdrom_spec["type"] == "iso" and iso_path is not None: - cdrom_device.backing = vim.vm.device.VirtualCdrom.IsoBackingInfo(fileName=iso_path) - cdrom_device.connectable = vim.vm.device.VirtualDevice.ConnectInfo() - cdrom_device.connectable.allowGuestControl = True - cdrom_device.connectable.startConnected = (cdrom_spec["type"] != "none") - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn: - cdrom_device.connectable.connected = (cdrom_spec["type"] != "none") - - def remove_cdrom(self, cdrom_device): - cdrom_spec = vim.vm.device.VirtualDeviceSpec() - cdrom_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.remove - cdrom_spec.device = cdrom_device - - return cdrom_spec - - def create_scsi_disk(self, scsi_ctl, disk_index=None): - diskspec = vim.vm.device.VirtualDeviceSpec() - diskspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add - diskspec.device = vim.vm.device.VirtualDisk() - diskspec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() - diskspec.device.controllerKey = scsi_ctl.device.key - - if self.next_disk_unit_number == 7: - raise AssertionError() - if disk_index == 7: - raise AssertionError() - """ - Configure disk unit number. - """ - if disk_index is not None: - diskspec.device.unitNumber = disk_index - self.next_disk_unit_number = disk_index + 1 - else: - diskspec.device.unitNumber = self.next_disk_unit_number - self.next_disk_unit_number += 1 - - # unit number 7 is reserved to SCSI controller, increase next index - if self.next_disk_unit_number == 7: - self.next_disk_unit_number += 1 - - return diskspec - - def get_device(self, device_type, name): - nic_dict = dict(pcnet32=vim.vm.device.VirtualPCNet32(), - vmxnet2=vim.vm.device.VirtualVmxnet2(), - vmxnet3=vim.vm.device.VirtualVmxnet3(), - e1000=vim.vm.device.VirtualE1000(), - e1000e=vim.vm.device.VirtualE1000e(), - sriov=vim.vm.device.VirtualSriovEthernetCard(), - ) - if device_type in nic_dict: - return nic_dict[device_type] - else: - self.module.fail_json(msg='Invalid device_type "%s"' - ' for network "%s"' % (device_type, name)) - - def create_nic(self, device_type, device_label, device_infos): - nic = vim.vm.device.VirtualDeviceSpec() - nic.device = self.get_device(device_type, device_infos['name']) - nic.device.wakeOnLanEnabled = bool(device_infos.get('wake_on_lan', True)) - nic.device.deviceInfo = vim.Description() - nic.device.deviceInfo.label = device_label - nic.device.deviceInfo.summary = device_infos['name'] - nic.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo() - nic.device.connectable.startConnected = bool(device_infos.get('start_connected', True)) - nic.device.connectable.allowGuestControl = bool(device_infos.get('allow_guest_control', True)) - nic.device.connectable.connected = True - if 'mac' in device_infos and is_mac(device_infos['mac']): - nic.device.addressType = 'manual' - nic.device.macAddress = device_infos['mac'] - else: - nic.device.addressType = 'generated' - - return nic - - def integer_value(self, input_value, name): - """ - Function to return int value for given input, else return error - Args: - input_value: Input value to retrieve int value from - name: Name of the Input value (used to build error message) - Returns: (int) if integer value can be obtained, otherwise will send a error message. - """ - if isinstance(input_value, int): - return input_value - elif isinstance(input_value, str) and input_value.isdigit(): - return int(input_value) - else: - self.module.fail_json(msg='"%s" attribute should be an' - ' integer value.' % name) - - -class PyVmomiCache(object): - """ This class caches references to objects which are requested multiples times but not modified """ - - def __init__(self, content, dc_name=None): - self.content = content - self.dc_name = dc_name - self.networks = {} - self.clusters = {} - self.esx_hosts = {} - self.parent_datacenters = {} - - def find_obj(self, content, types, name, confine_to_datacenter=True): - """ Wrapper around find_obj to set datacenter context """ - result = find_obj(content, types, name) - if result and confine_to_datacenter: - if to_text(self.get_parent_datacenter(result).name) != to_text(self.dc_name): - result = None - objects = self.get_all_objs(content, types, confine_to_datacenter=True) - for obj in objects: - if name is None or to_text(obj.name) == to_text(name): - return obj - return result - - def get_all_objs(self, content, types, confine_to_datacenter=True): - """ Wrapper around get_all_objs to set datacenter context """ - objects = get_all_objs(content, types) - if confine_to_datacenter: - if hasattr(objects, 'items'): - # resource pools come back as a dictionary - # make a copy - for k, v in tuple(objects.items()): - parent_dc = self.get_parent_datacenter(k) - if parent_dc.name != self.dc_name: - del objects[k] - else: - # everything else should be a list - objects = [x for x in objects if self.get_parent_datacenter(x).name == self.dc_name] - - return objects - - def get_network(self, network): - network = quote_obj_name(network) - - if network not in self.networks: - self.networks[network] = self.find_obj(self.content, [vim.Network], network) - - return self.networks[network] - - def get_cluster(self, cluster): - if cluster not in self.clusters: - self.clusters[cluster] = self.find_obj(self.content, [vim.ClusterComputeResource], cluster) - - return self.clusters[cluster] - - def get_esx_host(self, host): - if host not in self.esx_hosts: - self.esx_hosts[host] = self.find_obj(self.content, [vim.HostSystem], host) - - return self.esx_hosts[host] - - def get_parent_datacenter(self, obj): - """ Walk the parent tree to find the objects datacenter """ - if isinstance(obj, vim.Datacenter): - return obj - if obj in self.parent_datacenters: - return self.parent_datacenters[obj] - datacenter = None - while True: - if not hasattr(obj, 'parent'): - break - obj = obj.parent - if isinstance(obj, vim.Datacenter): - datacenter = obj - break - self.parent_datacenters[obj] = datacenter - return datacenter - - -class PyVmomiHelper(PyVmomi): - def __init__(self, module): - super(PyVmomiHelper, self).__init__(module) - self.device_helper = PyVmomiDeviceHelper(self.module) - self.configspec = None - self.relospec = None - self.change_detected = False # a change was detected and needs to be applied through reconfiguration - self.change_applied = False # a change was applied meaning at least one task succeeded - self.customspec = None - self.cache = PyVmomiCache(self.content, dc_name=self.params['datacenter']) - - def gather_facts(self, vm): - return gather_vm_facts(self.content, vm) - - def remove_vm(self, vm, delete_from_inventory=False): - # https://www.vmware.com/support/developer/converter-sdk/conv60_apireference/vim.ManagedEntity.html#destroy - if vm.summary.runtime.powerState.lower() == 'poweredon': - self.module.fail_json(msg="Virtual machine %s found in 'powered on' state, " - "please use 'force' parameter to remove or poweroff VM " - "and try removing VM again." % vm.name) - # Delete VM from Inventory - if delete_from_inventory: - try: - vm.UnregisterVM() - except (vim.fault.TaskInProgress, - vmodl.RuntimeFault) as e: - return {'changed': self.change_applied, 'failed': True, 'msg': e.msg, 'op': 'UnregisterVM'} - self.change_applied = True - return {'changed': self.change_applied, 'failed': False} - # Delete VM from Disk - task = vm.Destroy() - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'destroy'} - else: - return {'changed': self.change_applied, 'failed': False} - - def configure_guestid(self, vm_obj, vm_creation=False): - # guest_id is not required when using templates - if self.params['template']: - return - - # guest_id is only mandatory on VM creation - if vm_creation and self.params['guest_id'] is None: - self.module.fail_json(msg="guest_id attribute is mandatory for VM creation") - - if self.params['guest_id'] and \ - (vm_obj is None or self.params['guest_id'].lower() != vm_obj.summary.config.guestId.lower()): - self.change_detected = True - self.configspec.guestId = self.params['guest_id'] - - def configure_resource_alloc_info(self, vm_obj): - """ - Function to configure resource allocation information about virtual machine - :param vm_obj: VM object in case of reconfigure, None in case of deploy - :return: None - """ - rai_change_detected = False - memory_allocation = vim.ResourceAllocationInfo() - cpu_allocation = vim.ResourceAllocationInfo() - - if 'hardware' in self.params: - if 'mem_limit' in self.params['hardware']: - mem_limit = None - try: - mem_limit = int(self.params['hardware'].get('mem_limit')) - except ValueError: - self.module.fail_json(msg="hardware.mem_limit attribute should be an integer value.") - memory_allocation.limit = mem_limit - if vm_obj is None or memory_allocation.limit != vm_obj.config.memoryAllocation.limit: - rai_change_detected = True - - if 'mem_reservation' in self.params['hardware'] or 'memory_reservation' in self.params['hardware']: - mem_reservation = self.params['hardware'].get('mem_reservation') - if mem_reservation is None: - mem_reservation = self.params['hardware'].get('memory_reservation') - try: - mem_reservation = int(mem_reservation) - except ValueError: - self.module.fail_json(msg="hardware.mem_reservation or hardware.memory_reservation should be an integer value.") - - memory_allocation.reservation = mem_reservation - if vm_obj is None or \ - memory_allocation.reservation != vm_obj.config.memoryAllocation.reservation: - rai_change_detected = True - - if 'cpu_limit' in self.params['hardware']: - cpu_limit = None - try: - cpu_limit = int(self.params['hardware'].get('cpu_limit')) - except ValueError: - self.module.fail_json(msg="hardware.cpu_limit attribute should be an integer value.") - cpu_allocation.limit = cpu_limit - if vm_obj is None or cpu_allocation.limit != vm_obj.config.cpuAllocation.limit: - rai_change_detected = True - - if 'cpu_reservation' in self.params['hardware']: - cpu_reservation = None - try: - cpu_reservation = int(self.params['hardware'].get('cpu_reservation')) - except ValueError: - self.module.fail_json(msg="hardware.cpu_reservation should be an integer value.") - cpu_allocation.reservation = cpu_reservation - if vm_obj is None or \ - cpu_allocation.reservation != vm_obj.config.cpuAllocation.reservation: - rai_change_detected = True - - if rai_change_detected: - self.configspec.memoryAllocation = memory_allocation - self.configspec.cpuAllocation = cpu_allocation - self.change_detected = True - - def configure_cpu_and_memory(self, vm_obj, vm_creation=False): - # set cpu/memory/etc - if 'hardware' in self.params: - if 'num_cpus' in self.params['hardware']: - try: - num_cpus = int(self.params['hardware']['num_cpus']) - except ValueError: - self.module.fail_json(msg="hardware.num_cpus attribute should be an integer value.") - # check VM power state and cpu hot-add/hot-remove state before re-config VM - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn: - if not vm_obj.config.cpuHotRemoveEnabled and num_cpus < vm_obj.config.hardware.numCPU: - self.module.fail_json(msg="Configured cpu number is less than the cpu number of the VM, " - "cpuHotRemove is not enabled") - if not vm_obj.config.cpuHotAddEnabled and num_cpus > vm_obj.config.hardware.numCPU: - self.module.fail_json(msg="Configured cpu number is more than the cpu number of the VM, " - "cpuHotAdd is not enabled") - - if 'num_cpu_cores_per_socket' in self.params['hardware']: - try: - num_cpu_cores_per_socket = int(self.params['hardware']['num_cpu_cores_per_socket']) - except ValueError: - self.module.fail_json(msg="hardware.num_cpu_cores_per_socket attribute " - "should be an integer value.") - if num_cpus % num_cpu_cores_per_socket != 0: - self.module.fail_json(msg="hardware.num_cpus attribute should be a multiple " - "of hardware.num_cpu_cores_per_socket") - self.configspec.numCoresPerSocket = num_cpu_cores_per_socket - if vm_obj is None or self.configspec.numCoresPerSocket != vm_obj.config.hardware.numCoresPerSocket: - self.change_detected = True - self.configspec.numCPUs = num_cpus - if vm_obj is None or self.configspec.numCPUs != vm_obj.config.hardware.numCPU: - self.change_detected = True - # num_cpu is mandatory for VM creation - elif vm_creation and not self.params['template']: - self.module.fail_json(msg="hardware.num_cpus attribute is mandatory for VM creation") - - if 'memory_mb' in self.params['hardware']: - try: - memory_mb = int(self.params['hardware']['memory_mb']) - except ValueError: - self.module.fail_json(msg="Failed to parse hardware.memory_mb value." - " Please refer the documentation and provide" - " correct value.") - # check VM power state and memory hotadd state before re-config VM - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn: - if vm_obj.config.memoryHotAddEnabled and memory_mb < vm_obj.config.hardware.memoryMB: - self.module.fail_json(msg="Configured memory is less than memory size of the VM, " - "operation is not supported") - elif not vm_obj.config.memoryHotAddEnabled and memory_mb != vm_obj.config.hardware.memoryMB: - self.module.fail_json(msg="memoryHotAdd is not enabled") - self.configspec.memoryMB = memory_mb - if vm_obj is None or self.configspec.memoryMB != vm_obj.config.hardware.memoryMB: - self.change_detected = True - # memory_mb is mandatory for VM creation - elif vm_creation and not self.params['template']: - self.module.fail_json(msg="hardware.memory_mb attribute is mandatory for VM creation") - - if 'hotadd_memory' in self.params['hardware']: - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \ - vm_obj.config.memoryHotAddEnabled != bool(self.params['hardware']['hotadd_memory']): - self.module.fail_json(msg="Configure hotadd memory operation is not supported when VM is power on") - self.configspec.memoryHotAddEnabled = bool(self.params['hardware']['hotadd_memory']) - if vm_obj is None or self.configspec.memoryHotAddEnabled != vm_obj.config.memoryHotAddEnabled: - self.change_detected = True - - if 'hotadd_cpu' in self.params['hardware']: - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \ - vm_obj.config.cpuHotAddEnabled != bool(self.params['hardware']['hotadd_cpu']): - self.module.fail_json(msg="Configure hotadd cpu operation is not supported when VM is power on") - self.configspec.cpuHotAddEnabled = bool(self.params['hardware']['hotadd_cpu']) - if vm_obj is None or self.configspec.cpuHotAddEnabled != vm_obj.config.cpuHotAddEnabled: - self.change_detected = True - - if 'hotremove_cpu' in self.params['hardware']: - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn and \ - vm_obj.config.cpuHotRemoveEnabled != bool(self.params['hardware']['hotremove_cpu']): - self.module.fail_json(msg="Configure hotremove cpu operation is not supported when VM is power on") - self.configspec.cpuHotRemoveEnabled = bool(self.params['hardware']['hotremove_cpu']) - if vm_obj is None or self.configspec.cpuHotRemoveEnabled != vm_obj.config.cpuHotRemoveEnabled: - self.change_detected = True - - if 'memory_reservation_lock' in self.params['hardware']: - self.configspec.memoryReservationLockedToMax = bool(self.params['hardware']['memory_reservation_lock']) - if vm_obj is None or self.configspec.memoryReservationLockedToMax != vm_obj.config.memoryReservationLockedToMax: - self.change_detected = True - - if 'boot_firmware' in self.params['hardware']: - # boot firmware re-config can cause boot issue - if vm_obj is not None: - return - boot_firmware = self.params['hardware']['boot_firmware'].lower() - if boot_firmware not in ('bios', 'efi'): - self.module.fail_json(msg="hardware.boot_firmware value is invalid [%s]." - " Need one of ['bios', 'efi']." % boot_firmware) - self.configspec.firmware = boot_firmware - self.change_detected = True - - def sanitize_cdrom_params(self): - # cdroms {'ide': [{num: 0, cdrom: []}, {}], 'sata': [{num: 0, cdrom: []}, {}, ...]} - cdroms = {'ide': [], 'sata': []} - expected_cdrom_spec = self.params.get('cdrom') - if expected_cdrom_spec: - for cdrom_spec in expected_cdrom_spec: - cdrom_spec['controller_type'] = cdrom_spec.get('controller_type', 'ide').lower() - if cdrom_spec['controller_type'] not in ['ide', 'sata']: - self.module.fail_json(msg="Invalid cdrom.controller_type: %s, valid value is 'ide' or 'sata'." - % cdrom_spec['controller_type']) - - cdrom_spec['state'] = cdrom_spec.get('state', 'present').lower() - if cdrom_spec['state'] not in ['present', 'absent']: - self.module.fail_json(msg="Invalid cdrom.state: %s, valid value is 'present', 'absent'." - % cdrom_spec['state']) - - if cdrom_spec['state'] == 'present': - if 'type' in cdrom_spec and cdrom_spec.get('type') not in ['none', 'client', 'iso']: - self.module.fail_json(msg="Invalid cdrom.type: %s, valid value is 'none', 'client' or 'iso'." - % cdrom_spec.get('type')) - if cdrom_spec.get('type') == 'iso' and not cdrom_spec.get('iso_path'): - self.module.fail_json(msg="cdrom.iso_path is mandatory when cdrom.type is set to iso.") - - if cdrom_spec['controller_type'] == 'ide' and \ - (cdrom_spec.get('controller_number') not in [0, 1] or cdrom_spec.get('unit_number') not in [0, 1]): - self.module.fail_json(msg="Invalid cdrom.controller_number: %s or cdrom.unit_number: %s, valid" - " values are 0 or 1 for IDE controller." % (cdrom_spec.get('controller_number'), cdrom_spec.get('unit_number'))) - - if cdrom_spec['controller_type'] == 'sata' and \ - (cdrom_spec.get('controller_number') not in range(0, 4) or cdrom_spec.get('unit_number') not in range(0, 30)): - self.module.fail_json(msg="Invalid cdrom.controller_number: %s or cdrom.unit_number: %s," - " valid controller_number value is 0-3, valid unit_number is 0-29" - " for SATA controller." % (cdrom_spec.get('controller_number'), cdrom_spec.get('unit_number'))) - - ctl_exist = False - for exist_spec in cdroms.get(cdrom_spec['controller_type']): - if exist_spec['num'] == cdrom_spec['controller_number']: - ctl_exist = True - exist_spec['cdrom'].append(cdrom_spec) - break - if not ctl_exist: - cdroms.get(cdrom_spec['controller_type']).append({'num': cdrom_spec['controller_number'], 'cdrom': [cdrom_spec]}) - - return cdroms - - def configure_cdrom(self, vm_obj): - # Configure the VM CD-ROM - if self.params.get('cdrom'): - if vm_obj and vm_obj.config.template: - # Changing CD-ROM settings on a template is not supported - return - - if isinstance(self.params.get('cdrom'), dict): - self.configure_cdrom_dict(vm_obj) - elif isinstance(self.params.get('cdrom'), list): - self.configure_cdrom_list(vm_obj) - - def configure_cdrom_dict(self, vm_obj): - if self.params["cdrom"].get('type') not in ['none', 'client', 'iso']: - self.module.fail_json(msg="cdrom.type is mandatory. Options are 'none', 'client', and 'iso'.") - if self.params["cdrom"]['type'] == 'iso' and not self.params["cdrom"].get('iso_path'): - self.module.fail_json(msg="cdrom.iso_path is mandatory when cdrom.type is set to iso.") - - cdrom_spec = None - cdrom_devices = self.get_vm_cdrom_devices(vm=vm_obj) - iso_path = self.params["cdrom"].get("iso_path") - if len(cdrom_devices) == 0: - # Creating new CD-ROM - ide_devices = self.get_vm_ide_devices(vm=vm_obj) - if len(ide_devices) == 0: - # Creating new IDE device - ide_ctl = self.device_helper.create_ide_controller() - ide_device = ide_ctl.device - self.change_detected = True - self.configspec.deviceChange.append(ide_ctl) - else: - ide_device = ide_devices[0] - if len(ide_device.device) > 3: - self.module.fail_json(msg="hardware.cdrom specified for a VM or template which already has 4" - " IDE devices of which none are a cdrom") - - cdrom_spec = self.device_helper.create_cdrom(ide_device=ide_device, cdrom_type=self.params["cdrom"]["type"], - iso_path=iso_path) - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn: - cdrom_spec.device.connectable.connected = (self.params["cdrom"]["type"] != "none") - - elif not self.device_helper.is_equal_cdrom(vm_obj=vm_obj, cdrom_device=cdrom_devices[0], - cdrom_type=self.params["cdrom"]["type"], iso_path=iso_path): - self.device_helper.update_cdrom_config(vm_obj, self.params["cdrom"], cdrom_devices[0], iso_path=iso_path) - cdrom_spec = vim.vm.device.VirtualDeviceSpec() - cdrom_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit - cdrom_spec.device = cdrom_devices[0] - - if cdrom_spec: - self.change_detected = True - self.configspec.deviceChange.append(cdrom_spec) - - def configure_cdrom_list(self, vm_obj): - configured_cdroms = self.sanitize_cdrom_params() - cdrom_devices = self.get_vm_cdrom_devices(vm=vm_obj) - # configure IDE CD-ROMs - if configured_cdroms['ide']: - ide_devices = self.get_vm_ide_devices(vm=vm_obj) - for expected_cdrom_spec in configured_cdroms['ide']: - ide_device = None - for device in ide_devices: - if device.busNumber == expected_cdrom_spec['num']: - ide_device = device - break - # if not find the matched ide controller or no existing ide controller - if not ide_device: - ide_ctl = self.device_helper.create_ide_controller(bus_number=expected_cdrom_spec['num']) - ide_device = ide_ctl.device - self.change_detected = True - self.configspec.deviceChange.append(ide_ctl) - - for cdrom in expected_cdrom_spec['cdrom']: - cdrom_device = None - iso_path = cdrom.get('iso_path') - unit_number = cdrom.get('unit_number') - for target_cdrom in cdrom_devices: - if target_cdrom.controllerKey == ide_device.key and target_cdrom.unitNumber == unit_number: - cdrom_device = target_cdrom - break - # create new CD-ROM - if not cdrom_device and cdrom.get('state') != 'absent': - if vm_obj and vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOn: - self.module.fail_json(msg='CD-ROM attach to IDE controller not support hot-add.') - if len(ide_device.device) == 2: - self.module.fail_json(msg='Maximum number of CD-ROMs attached to IDE controller is 2.') - cdrom_spec = self.device_helper.create_cdrom(ide_device=ide_device, cdrom_type=cdrom['type'], - iso_path=iso_path, unit_number=unit_number) - self.change_detected = True - self.configspec.deviceChange.append(cdrom_spec) - # re-configure CD-ROM - elif cdrom_device and cdrom.get('state') != 'absent' and \ - not self.device_helper.is_equal_cdrom(vm_obj=vm_obj, cdrom_device=cdrom_device, - cdrom_type=cdrom['type'], iso_path=iso_path): - self.device_helper.update_cdrom_config(vm_obj, cdrom, cdrom_device, iso_path=iso_path) - cdrom_spec = vim.vm.device.VirtualDeviceSpec() - cdrom_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit - cdrom_spec.device = cdrom_device - self.change_detected = True - self.configspec.deviceChange.append(cdrom_spec) - # delete CD-ROM - elif cdrom_device and cdrom.get('state') == 'absent': - if vm_obj and vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOff: - self.module.fail_json(msg='CD-ROM attach to IDE controller not support hot-remove.') - cdrom_spec = self.device_helper.remove_cdrom(cdrom_device) - self.change_detected = True - self.configspec.deviceChange.append(cdrom_spec) - # configure SATA CD-ROMs is not supported yet - if configured_cdroms['sata']: - pass - - def configure_hardware_params(self, vm_obj): - """ - Function to configure hardware related configuration of virtual machine - Args: - vm_obj: virtual machine object - """ - if 'hardware' in self.params: - if 'max_connections' in self.params['hardware']: - # maxMksConnections == max_connections - self.configspec.maxMksConnections = int(self.params['hardware']['max_connections']) - if vm_obj is None or self.configspec.maxMksConnections != vm_obj.config.maxMksConnections: - self.change_detected = True - - if 'nested_virt' in self.params['hardware']: - self.configspec.nestedHVEnabled = bool(self.params['hardware']['nested_virt']) - if vm_obj is None or self.configspec.nestedHVEnabled != bool(vm_obj.config.nestedHVEnabled): - self.change_detected = True - - if 'version' in self.params['hardware']: - hw_version_check_failed = False - temp_version = self.params['hardware'].get('version', 10) - if isinstance(temp_version, str) and temp_version.lower() == 'latest': - # Check is to make sure vm_obj is not of type template - if vm_obj and not vm_obj.config.template: - try: - task = vm_obj.UpgradeVM_Task() - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'upgrade'} - except vim.fault.AlreadyUpgraded: - # Don't fail if VM is already upgraded. - pass - else: - try: - temp_version = int(temp_version) - except ValueError: - hw_version_check_failed = True - - if temp_version not in range(3, 16): - hw_version_check_failed = True - - if hw_version_check_failed: - self.module.fail_json(msg="Failed to set hardware.version '%s' value as valid" - " values range from 3 (ESX 2.x) to 14 (ESXi 6.5 and greater)." % temp_version) - # Hardware version is denoted as "vmx-10" - version = "vmx-%02d" % temp_version - self.configspec.version = version - if vm_obj is None or self.configspec.version != vm_obj.config.version: - self.change_detected = True - # Check is to make sure vm_obj is not of type template - if vm_obj and not vm_obj.config.template: - # VM exists and we need to update the hardware version - current_version = vm_obj.config.version - # current_version = "vmx-10" - version_digit = int(current_version.split("-", 1)[-1]) - if temp_version < version_digit: - self.module.fail_json(msg="Current hardware version '%d' which is greater than the specified" - " version '%d'. Downgrading hardware version is" - " not supported. Please specify version greater" - " than the current version." % (version_digit, - temp_version)) - new_version = "vmx-%02d" % temp_version - try: - task = vm_obj.UpgradeVM_Task(new_version) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'upgrade'} - except vim.fault.AlreadyUpgraded: - # Don't fail if VM is already upgraded. - pass - - if 'virt_based_security' in self.params['hardware']: - host_version = self.select_host().summary.config.product.version - if int(host_version.split('.')[0]) < 6 or (int(host_version.split('.')[0]) == 6 and int(host_version.split('.')[1]) < 7): - self.module.fail_json(msg="ESXi version %s not support VBS." % host_version) - guest_ids = ['windows9_64Guest', 'windows9Server64Guest'] - if vm_obj is None: - guestid = self.configspec.guestId - else: - guestid = vm_obj.summary.config.guestId - if guestid not in guest_ids: - self.module.fail_json(msg="Guest '%s' not support VBS." % guestid) - if (vm_obj is None and int(self.configspec.version.split('-')[1]) >= 14) or \ - (vm_obj and int(vm_obj.config.version.split('-')[1]) >= 14 and (vm_obj.runtime.powerState == vim.VirtualMachinePowerState.poweredOff)): - self.configspec.flags = vim.vm.FlagInfo() - self.configspec.flags.vbsEnabled = bool(self.params['hardware']['virt_based_security']) - if bool(self.params['hardware']['virt_based_security']): - self.configspec.flags.vvtdEnabled = True - self.configspec.nestedHVEnabled = True - if (vm_obj is None and self.configspec.firmware == 'efi') or \ - (vm_obj and vm_obj.config.firmware == 'efi'): - self.configspec.bootOptions = vim.vm.BootOptions() - self.configspec.bootOptions.efiSecureBootEnabled = True - else: - self.module.fail_json(msg="Not support VBS when firmware is BIOS.") - if vm_obj is None or self.configspec.flags.vbsEnabled != vm_obj.config.flags.vbsEnabled: - self.change_detected = True - - def get_device_by_type(self, vm=None, type=None): - device_list = [] - if vm is None or type is None: - return device_list - for device in vm.config.hardware.device: - if isinstance(device, type): - device_list.append(device) - - return device_list - - def get_vm_cdrom_devices(self, vm=None): - return self.get_device_by_type(vm=vm, type=vim.vm.device.VirtualCdrom) - - def get_vm_ide_devices(self, vm=None): - return self.get_device_by_type(vm=vm, type=vim.vm.device.VirtualIDEController) - - def get_vm_network_interfaces(self, vm=None): - device_list = [] - if vm is None: - return device_list - - nw_device_types = (vim.vm.device.VirtualPCNet32, vim.vm.device.VirtualVmxnet2, - vim.vm.device.VirtualVmxnet3, vim.vm.device.VirtualE1000, - vim.vm.device.VirtualE1000e, vim.vm.device.VirtualSriovEthernetCard) - for device in vm.config.hardware.device: - if isinstance(device, nw_device_types): - device_list.append(device) - - return device_list - - def sanitize_network_params(self): - """ - Sanitize user provided network provided params - - Returns: A sanitized list of network params, else fails - - """ - network_devices = list() - # Clean up user data here - for network in self.params['networks']: - if 'name' not in network and 'vlan' not in network: - self.module.fail_json(msg="Please specify at least a network name or" - " a VLAN name under VM network list.") - - if 'name' in network and self.cache.get_network(network['name']) is None: - self.module.fail_json(msg="Network '%(name)s' does not exist." % network) - elif 'vlan' in network: - dvps = self.cache.get_all_objs(self.content, [vim.dvs.DistributedVirtualPortgroup]) - for dvp in dvps: - if hasattr(dvp.config.defaultPortConfig, 'vlan') and \ - isinstance(dvp.config.defaultPortConfig.vlan.vlanId, int) and \ - str(dvp.config.defaultPortConfig.vlan.vlanId) == str(network['vlan']): - network['name'] = dvp.config.name - break - if 'dvswitch_name' in network and \ - dvp.config.distributedVirtualSwitch.name == network['dvswitch_name'] and \ - dvp.config.name == network['vlan']: - network['name'] = dvp.config.name - break - - if dvp.config.name == network['vlan']: - network['name'] = dvp.config.name - break - else: - self.module.fail_json(msg="VLAN '%(vlan)s' does not exist." % network) - - if 'type' in network: - if network['type'] not in ['dhcp', 'static']: - self.module.fail_json(msg="Network type '%(type)s' is not a valid parameter." - " Valid parameters are ['dhcp', 'static']." % network) - if network['type'] != 'static' and ('ip' in network or 'netmask' in network): - self.module.fail_json(msg='Static IP information provided for network "%(name)s",' - ' but "type" is set to "%(type)s".' % network) - else: - # Type is optional parameter, if user provided IP or Subnet assume - # network type as 'static' - if 'ip' in network or 'netmask' in network: - network['type'] = 'static' - else: - # User wants network type as 'dhcp' - network['type'] = 'dhcp' - - if network.get('type') == 'static': - if 'ip' in network and 'netmask' not in network: - self.module.fail_json(msg="'netmask' is required if 'ip' is" - " specified under VM network list.") - if 'ip' not in network and 'netmask' in network: - self.module.fail_json(msg="'ip' is required if 'netmask' is" - " specified under VM network list.") - - validate_device_types = ['pcnet32', 'vmxnet2', 'vmxnet3', 'e1000', 'e1000e', 'sriov'] - if 'device_type' in network and network['device_type'] not in validate_device_types: - self.module.fail_json(msg="Device type specified '%s' is not valid." - " Please specify correct device" - " type from ['%s']." % (network['device_type'], - "', '".join(validate_device_types))) - - if 'mac' in network and not is_mac(network['mac']): - self.module.fail_json(msg="Device MAC address '%s' is invalid." - " Please provide correct MAC address." % network['mac']) - - network_devices.append(network) - - return network_devices - - def configure_network(self, vm_obj): - # Ignore empty networks, this permits to keep networks when deploying a template/cloning a VM - if len(self.params['networks']) == 0: - return - - network_devices = self.sanitize_network_params() - - # List current device for Clone or Idempotency - current_net_devices = self.get_vm_network_interfaces(vm=vm_obj) - if len(network_devices) < len(current_net_devices): - self.module.fail_json(msg="Given network device list is lesser than current VM device list (%d < %d). " - "Removing interfaces is not allowed" - % (len(network_devices), len(current_net_devices))) - - for key in range(0, len(network_devices)): - nic_change_detected = False - network_name = network_devices[key]['name'] - if key < len(current_net_devices) and (vm_obj or self.params['template']): - # We are editing existing network devices, this is either when - # are cloning from VM or Template - nic = vim.vm.device.VirtualDeviceSpec() - nic.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit - - nic.device = current_net_devices[key] - if ('wake_on_lan' in network_devices[key] and - nic.device.wakeOnLanEnabled != network_devices[key].get('wake_on_lan')): - nic.device.wakeOnLanEnabled = network_devices[key].get('wake_on_lan') - nic_change_detected = True - if ('start_connected' in network_devices[key] and - nic.device.connectable.startConnected != network_devices[key].get('start_connected')): - nic.device.connectable.startConnected = network_devices[key].get('start_connected') - nic_change_detected = True - if ('allow_guest_control' in network_devices[key] and - nic.device.connectable.allowGuestControl != network_devices[key].get('allow_guest_control')): - nic.device.connectable.allowGuestControl = network_devices[key].get('allow_guest_control') - nic_change_detected = True - - if nic.device.deviceInfo.summary != network_name: - nic.device.deviceInfo.summary = network_name - nic_change_detected = True - if 'device_type' in network_devices[key]: - device = self.device_helper.get_device(network_devices[key]['device_type'], network_name) - device_class = type(device) - if not isinstance(nic.device, device_class): - self.module.fail_json(msg="Changing the device type is not possible when interface is already present. " - "The failing device type is %s" % network_devices[key]['device_type']) - # Changing mac address has no effect when editing interface - if 'mac' in network_devices[key] and nic.device.macAddress != current_net_devices[key].macAddress: - self.module.fail_json(msg="Changing MAC address has not effect when interface is already present. " - "The failing new MAC address is %s" % nic.device.macAddress) - - else: - # Default device type is vmxnet3, VMware best practice - device_type = network_devices[key].get('device_type', 'vmxnet3') - nic = self.device_helper.create_nic(device_type, - 'Network Adapter %s' % (key + 1), - network_devices[key]) - nic.operation = vim.vm.device.VirtualDeviceSpec.Operation.add - nic_change_detected = True - - if hasattr(self.cache.get_network(network_name), 'portKeys'): - # VDS switch - - pg_obj = None - if 'dvswitch_name' in network_devices[key]: - dvs_name = network_devices[key]['dvswitch_name'] - dvs_obj = find_dvs_by_name(self.content, dvs_name) - if dvs_obj is None: - self.module.fail_json(msg="Unable to find distributed virtual switch %s" % dvs_name) - pg_obj = find_dvspg_by_name(dvs_obj, network_name) - if pg_obj is None: - self.module.fail_json(msg="Unable to find distributed port group %s" % network_name) - else: - pg_obj = self.cache.find_obj(self.content, [vim.dvs.DistributedVirtualPortgroup], network_name) - - # TODO: (akasurde) There is no way to find association between resource pool and distributed virtual portgroup - # For now, check if we are able to find distributed virtual switch - if not pg_obj.config.distributedVirtualSwitch: - self.module.fail_json(msg="Failed to find distributed virtual switch which is associated with" - " distributed virtual portgroup '%s'. Make sure hostsystem is associated with" - " the given distributed virtual portgroup. Also, check if user has correct" - " permission to access distributed virtual switch in the given portgroup." % pg_obj.name) - if (nic.device.backing and - (not hasattr(nic.device.backing, 'port') or - (nic.device.backing.port.portgroupKey != pg_obj.key or - nic.device.backing.port.switchUuid != pg_obj.config.distributedVirtualSwitch.uuid))): - nic_change_detected = True - - dvs_port_connection = vim.dvs.PortConnection() - dvs_port_connection.portgroupKey = pg_obj.key - # If user specifies distributed port group without associating to the hostsystem on which - # virtual machine is going to be deployed then we get error. We can infer that there is no - # association between given distributed port group and host system. - host_system = self.params.get('esxi_hostname') - if host_system and host_system not in [host.config.host.name for host in pg_obj.config.distributedVirtualSwitch.config.host]: - self.module.fail_json(msg="It seems that host system '%s' is not associated with distributed" - " virtual portgroup '%s'. Please make sure host system is associated" - " with given distributed virtual portgroup" % (host_system, pg_obj.name)) - dvs_port_connection.switchUuid = pg_obj.config.distributedVirtualSwitch.uuid - nic.device.backing = vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo() - nic.device.backing.port = dvs_port_connection - - elif isinstance(self.cache.get_network(network_name), vim.OpaqueNetwork): - # NSX-T Logical Switch - nic.device.backing = vim.vm.device.VirtualEthernetCard.OpaqueNetworkBackingInfo() - network_id = self.cache.get_network(network_name).summary.opaqueNetworkId - nic.device.backing.opaqueNetworkType = 'nsx.LogicalSwitch' - nic.device.backing.opaqueNetworkId = network_id - nic.device.deviceInfo.summary = 'nsx.LogicalSwitch: %s' % network_id - nic_change_detected = True - else: - # vSwitch - if not isinstance(nic.device.backing, vim.vm.device.VirtualEthernetCard.NetworkBackingInfo): - nic.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo() - nic_change_detected = True - - net_obj = self.cache.get_network(network_name) - if nic.device.backing.network != net_obj: - nic.device.backing.network = net_obj - nic_change_detected = True - - if nic.device.backing.deviceName != network_name: - nic.device.backing.deviceName = network_name - nic_change_detected = True - - if nic_change_detected: - # Change to fix the issue found while configuring opaque network - # VMs cloned from a template with opaque network will get disconnected - # Replacing deprecated config parameter with relocation Spec - if isinstance(self.cache.get_network(network_name), vim.OpaqueNetwork): - self.relospec.deviceChange.append(nic) - else: - self.configspec.deviceChange.append(nic) - self.change_detected = True - - def configure_vapp_properties(self, vm_obj): - if len(self.params['vapp_properties']) == 0: - return - - for x in self.params['vapp_properties']: - if not x.get('id'): - self.module.fail_json(msg="id is required to set vApp property") - - new_vmconfig_spec = vim.vApp.VmConfigSpec() - - if vm_obj: - # VM exists - # This is primarily for vcsim/integration tests, unset vAppConfig was not seen on my deployments - orig_spec = vm_obj.config.vAppConfig if vm_obj.config.vAppConfig else new_vmconfig_spec - - vapp_properties_current = dict((x.id, x) for x in orig_spec.property) - vapp_properties_to_change = dict((x['id'], x) for x in self.params['vapp_properties']) - - # each property must have a unique key - # init key counter with max value + 1 - all_keys = [x.key for x in orig_spec.property] - new_property_index = max(all_keys) + 1 if all_keys else 0 - - for property_id, property_spec in vapp_properties_to_change.items(): - is_property_changed = False - new_vapp_property_spec = vim.vApp.PropertySpec() - - if property_id in vapp_properties_current: - if property_spec.get('operation') == 'remove': - new_vapp_property_spec.operation = 'remove' - new_vapp_property_spec.removeKey = vapp_properties_current[property_id].key - is_property_changed = True - else: - # this is 'edit' branch - new_vapp_property_spec.operation = 'edit' - new_vapp_property_spec.info = vapp_properties_current[property_id] - try: - for property_name, property_value in property_spec.items(): - - if property_name == 'operation': - # operation is not an info object property - # if set to anything other than 'remove' we don't fail - continue - - # Updating attributes only if needed - if getattr(new_vapp_property_spec.info, property_name) != property_value: - setattr(new_vapp_property_spec.info, property_name, property_value) - is_property_changed = True - - except Exception as e: - msg = "Failed to set vApp property field='%s' and value='%s'. Error: %s" % (property_name, property_value, to_text(e)) - self.module.fail_json(msg=msg) - else: - if property_spec.get('operation') == 'remove': - # attempt to delete non-existent property - continue - - # this is add new property branch - new_vapp_property_spec.operation = 'add' - - property_info = vim.vApp.PropertyInfo() - property_info.classId = property_spec.get('classId') - property_info.instanceId = property_spec.get('instanceId') - property_info.id = property_spec.get('id') - property_info.category = property_spec.get('category') - property_info.label = property_spec.get('label') - property_info.type = property_spec.get('type', 'string') - property_info.userConfigurable = property_spec.get('userConfigurable', True) - property_info.defaultValue = property_spec.get('defaultValue') - property_info.value = property_spec.get('value', '') - property_info.description = property_spec.get('description') - - new_vapp_property_spec.info = property_info - new_vapp_property_spec.info.key = new_property_index - new_property_index += 1 - is_property_changed = True - - if is_property_changed: - new_vmconfig_spec.property.append(new_vapp_property_spec) - else: - # New VM - all_keys = [x.key for x in new_vmconfig_spec.property] - new_property_index = max(all_keys) + 1 if all_keys else 0 - vapp_properties_to_change = dict((x['id'], x) for x in self.params['vapp_properties']) - is_property_changed = False - - for property_id, property_spec in vapp_properties_to_change.items(): - new_vapp_property_spec = vim.vApp.PropertySpec() - # this is add new property branch - new_vapp_property_spec.operation = 'add' - - property_info = vim.vApp.PropertyInfo() - property_info.classId = property_spec.get('classId') - property_info.instanceId = property_spec.get('instanceId') - property_info.id = property_spec.get('id') - property_info.category = property_spec.get('category') - property_info.label = property_spec.get('label') - property_info.type = property_spec.get('type', 'string') - property_info.userConfigurable = property_spec.get('userConfigurable', True) - property_info.defaultValue = property_spec.get('defaultValue') - property_info.value = property_spec.get('value', '') - property_info.description = property_spec.get('description') - - new_vapp_property_spec.info = property_info - new_vapp_property_spec.info.key = new_property_index - new_property_index += 1 - is_property_changed = True - - if is_property_changed: - new_vmconfig_spec.property.append(new_vapp_property_spec) - - if new_vmconfig_spec.property: - self.configspec.vAppConfig = new_vmconfig_spec - self.change_detected = True - - def customize_customvalues(self, vm_obj, config_spec): - if len(self.params['customvalues']) == 0: - return - - vm_custom_spec = config_spec - vm_custom_spec.extraConfig = [] - - changed = False - facts = self.gather_facts(vm_obj) - for kv in self.params['customvalues']: - if 'key' not in kv or 'value' not in kv: - self.module.exit_json(msg="customvalues items required both 'key' and 'value' fields.") - - # If kv is not kv fetched from facts, change it - if kv['key'] not in facts['customvalues'] or facts['customvalues'][kv['key']] != kv['value']: - option = vim.option.OptionValue() - option.key = kv['key'] - option.value = kv['value'] - - vm_custom_spec.extraConfig.append(option) - changed = True - - if changed: - self.change_detected = True - - def customize_vm(self, vm_obj): - - # User specified customization specification - custom_spec_name = self.params.get('customization_spec') - if custom_spec_name: - cc_mgr = self.content.customizationSpecManager - if cc_mgr.DoesCustomizationSpecExist(name=custom_spec_name): - temp_spec = cc_mgr.GetCustomizationSpec(name=custom_spec_name) - self.customspec = temp_spec.spec - return - else: - self.module.fail_json(msg="Unable to find customization specification" - " '%s' in given configuration." % custom_spec_name) - - # Network settings - adaptermaps = [] - for network in self.params['networks']: - - guest_map = vim.vm.customization.AdapterMapping() - guest_map.adapter = vim.vm.customization.IPSettings() - - if 'ip' in network and 'netmask' in network: - guest_map.adapter.ip = vim.vm.customization.FixedIp() - guest_map.adapter.ip.ipAddress = str(network['ip']) - guest_map.adapter.subnetMask = str(network['netmask']) - elif 'type' in network and network['type'] == 'dhcp': - guest_map.adapter.ip = vim.vm.customization.DhcpIpGenerator() - - if 'gateway' in network: - guest_map.adapter.gateway = network['gateway'] - - # On Windows, DNS domain and DNS servers can be set by network interface - # https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.IPSettings.html - if 'domain' in network: - guest_map.adapter.dnsDomain = network['domain'] - elif 'domain' in self.params['customization']: - guest_map.adapter.dnsDomain = self.params['customization']['domain'] - - if 'dns_servers' in network: - guest_map.adapter.dnsServerList = network['dns_servers'] - elif 'dns_servers' in self.params['customization']: - guest_map.adapter.dnsServerList = self.params['customization']['dns_servers'] - - adaptermaps.append(guest_map) - - # Global DNS settings - globalip = vim.vm.customization.GlobalIPSettings() - if 'dns_servers' in self.params['customization']: - globalip.dnsServerList = self.params['customization']['dns_servers'] - - # TODO: Maybe list the different domains from the interfaces here by default ? - if 'dns_suffix' in self.params['customization']: - dns_suffix = self.params['customization']['dns_suffix'] - if isinstance(dns_suffix, list): - globalip.dnsSuffixList = " ".join(dns_suffix) - else: - globalip.dnsSuffixList = dns_suffix - elif 'domain' in self.params['customization']: - globalip.dnsSuffixList = self.params['customization']['domain'] - - if self.params['guest_id']: - guest_id = self.params['guest_id'] - else: - guest_id = vm_obj.summary.config.guestId - - # For windows guest OS, use SysPrep - # https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.Sysprep.html#field_detail - if 'win' in guest_id: - ident = vim.vm.customization.Sysprep() - - ident.userData = vim.vm.customization.UserData() - - # Setting hostName, orgName and fullName is mandatory, so we set some default when missing - ident.userData.computerName = vim.vm.customization.FixedName() - # computer name will be truncated to 15 characters if using VM name - default_name = self.params['name'].replace(' ', '') - punctuation = string.punctuation.replace('-', '') - default_name = ''.join([c for c in default_name if c not in punctuation]) - ident.userData.computerName.name = str(self.params['customization'].get('hostname', default_name[0:15])) - ident.userData.fullName = str(self.params['customization'].get('fullname', 'Administrator')) - ident.userData.orgName = str(self.params['customization'].get('orgname', 'ACME')) - - if 'productid' in self.params['customization']: - ident.userData.productId = str(self.params['customization']['productid']) - - ident.guiUnattended = vim.vm.customization.GuiUnattended() - - if 'autologon' in self.params['customization']: - ident.guiUnattended.autoLogon = self.params['customization']['autologon'] - ident.guiUnattended.autoLogonCount = self.params['customization'].get('autologoncount', 1) - - if 'timezone' in self.params['customization']: - # Check if timezone value is a int before proceeding. - ident.guiUnattended.timeZone = self.device_helper.integer_value( - self.params['customization']['timezone'], - 'customization.timezone') - - ident.identification = vim.vm.customization.Identification() - - if self.params['customization'].get('password', '') != '': - ident.guiUnattended.password = vim.vm.customization.Password() - ident.guiUnattended.password.value = str(self.params['customization']['password']) - ident.guiUnattended.password.plainText = True - - if 'joindomain' in self.params['customization']: - if 'domainadmin' not in self.params['customization'] or 'domainadminpassword' not in self.params['customization']: - self.module.fail_json(msg="'domainadmin' and 'domainadminpassword' entries are mandatory in 'customization' section to use " - "joindomain feature") - - ident.identification.domainAdmin = str(self.params['customization']['domainadmin']) - ident.identification.joinDomain = str(self.params['customization']['joindomain']) - ident.identification.domainAdminPassword = vim.vm.customization.Password() - ident.identification.domainAdminPassword.value = str(self.params['customization']['domainadminpassword']) - ident.identification.domainAdminPassword.plainText = True - - elif 'joinworkgroup' in self.params['customization']: - ident.identification.joinWorkgroup = str(self.params['customization']['joinworkgroup']) - - if 'runonce' in self.params['customization']: - ident.guiRunOnce = vim.vm.customization.GuiRunOnce() - ident.guiRunOnce.commandList = self.params['customization']['runonce'] - - else: - # FIXME: We have no clue whether this non-Windows OS is actually Linux, hence it might fail! - - # For Linux guest OS, use LinuxPrep - # https://pubs.vmware.com/vi3/sdk/ReferenceGuide/vim.vm.customization.LinuxPrep.html - ident = vim.vm.customization.LinuxPrep() - - # TODO: Maybe add domain from interface if missing ? - if 'domain' in self.params['customization']: - ident.domain = str(self.params['customization']['domain']) - - ident.hostName = vim.vm.customization.FixedName() - hostname = str(self.params['customization'].get('hostname', self.params['name'].split('.')[0])) - # Remove all characters except alphanumeric and minus which is allowed by RFC 952 - valid_hostname = re.sub(r"[^a-zA-Z0-9\-]", "", hostname) - ident.hostName.name = valid_hostname - - # List of supported time zones for different vSphere versions in Linux/Unix systems - # https://kb.vmware.com/s/article/2145518 - if 'timezone' in self.params['customization']: - ident.timeZone = str(self.params['customization']['timezone']) - if 'hwclockUTC' in self.params['customization']: - ident.hwClockUTC = self.params['customization']['hwclockUTC'] - - self.customspec = vim.vm.customization.Specification() - self.customspec.nicSettingMap = adaptermaps - self.customspec.globalIPSettings = globalip - self.customspec.identity = ident - - def get_vm_scsi_controller(self, vm_obj): - # If vm_obj doesn't exist there is no SCSI controller to find - if vm_obj is None: - return None - - for device in vm_obj.config.hardware.device: - if self.device_helper.is_scsi_controller(device): - scsi_ctl = vim.vm.device.VirtualDeviceSpec() - scsi_ctl.device = device - return scsi_ctl - - return None - - def get_configured_disk_size(self, expected_disk_spec): - # what size is it? - if [x for x in expected_disk_spec.keys() if x.startswith('size_') or x == 'size']: - # size, size_tb, size_gb, size_mb, size_kb - if 'size' in expected_disk_spec: - size_regex = re.compile(r'(\d+(?:\.\d+)?)([tgmkTGMK][bB])') - disk_size_m = size_regex.match(expected_disk_spec['size']) - try: - if disk_size_m: - expected = disk_size_m.group(1) - unit = disk_size_m.group(2) - else: - raise ValueError - - if re.match(r'\d+\.\d+', expected): - # We found float value in string, let's typecast it - expected = float(expected) - else: - # We found int value in string, let's typecast it - expected = int(expected) - - if not expected or not unit: - raise ValueError - - except (TypeError, ValueError, NameError): - # Common failure - self.module.fail_json(msg="Failed to parse disk size please review value" - " provided using documentation.") - else: - param = [x for x in expected_disk_spec.keys() if x.startswith('size_')][0] - unit = param.split('_')[-1].lower() - expected = [x[1] for x in expected_disk_spec.items() if x[0].startswith('size_')][0] - expected = int(expected) - - disk_units = dict(tb=3, gb=2, mb=1, kb=0) - if unit in disk_units: - unit = unit.lower() - return expected * (1024 ** disk_units[unit]) - else: - self.module.fail_json(msg="%s is not a supported unit for disk size." - " Supported units are ['%s']." % (unit, - "', '".join(disk_units.keys()))) - - # No size found but disk, fail - self.module.fail_json( - msg="No size, size_kb, size_mb, size_gb or size_tb attribute found into disk configuration") - - def add_existing_vmdk(self, vm_obj, expected_disk_spec, diskspec, scsi_ctl): - """ - Adds vmdk file described by expected_disk_spec['filename'], retrieves the file - information and adds the correct spec to self.configspec.deviceChange. - """ - filename = expected_disk_spec['filename'] - # If this is a new disk, or the disk file names are different - if (vm_obj and diskspec.device.backing.fileName != filename) or vm_obj is None: - diskspec.device.backing.fileName = filename - diskspec.device.key = -1 - self.change_detected = True - self.configspec.deviceChange.append(diskspec) - - def configure_disks(self, vm_obj): - # Ignore empty disk list, this permits to keep disks when deploying a template/cloning a VM - if len(self.params['disk']) == 0: - return - - scsi_ctl = self.get_vm_scsi_controller(vm_obj) - - # Create scsi controller only if we are deploying a new VM, not a template or reconfiguring - if vm_obj is None or scsi_ctl is None: - scsi_ctl = self.device_helper.create_scsi_controller(self.get_scsi_type()) - self.change_detected = True - self.configspec.deviceChange.append(scsi_ctl) - - disks = [x for x in vm_obj.config.hardware.device if isinstance(x, vim.vm.device.VirtualDisk)] \ - if vm_obj is not None else None - - if disks is not None and self.params.get('disk') and len(self.params.get('disk')) < len(disks): - self.module.fail_json(msg="Provided disks configuration has less disks than " - "the target object (%d vs %d)" % (len(self.params.get('disk')), len(disks))) - - disk_index = 0 - for expected_disk_spec in self.params.get('disk'): - disk_modified = False - # If we are manipulating and existing objects which has disks and disk_index is in disks - if vm_obj is not None and disks is not None and disk_index < len(disks): - diskspec = vim.vm.device.VirtualDeviceSpec() - # set the operation to edit so that it knows to keep other settings - diskspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit - diskspec.device = disks[disk_index] - else: - diskspec = self.device_helper.create_scsi_disk(scsi_ctl, disk_index) - disk_modified = True - - # increment index for next disk search - disk_index += 1 - # index 7 is reserved to SCSI controller - if disk_index == 7: - disk_index += 1 - - if 'disk_mode' in expected_disk_spec: - disk_mode = expected_disk_spec.get('disk_mode', 'persistent').lower() - valid_disk_mode = ['persistent', 'independent_persistent', 'independent_nonpersistent'] - if disk_mode not in valid_disk_mode: - self.module.fail_json(msg="disk_mode specified is not valid." - " Should be one of ['%s']" % "', '".join(valid_disk_mode)) - - if (vm_obj and diskspec.device.backing.diskMode != disk_mode) or (vm_obj is None): - diskspec.device.backing.diskMode = disk_mode - disk_modified = True - else: - diskspec.device.backing.diskMode = "persistent" - - # is it thin? - if 'type' in expected_disk_spec: - disk_type = expected_disk_spec.get('type', '').lower() - if disk_type == 'thin': - diskspec.device.backing.thinProvisioned = True - elif disk_type == 'eagerzeroedthick': - diskspec.device.backing.eagerlyScrub = True - - if 'filename' in expected_disk_spec and expected_disk_spec['filename'] is not None: - self.add_existing_vmdk(vm_obj, expected_disk_spec, diskspec, scsi_ctl) - continue - elif vm_obj is None or self.params['template']: - # We are creating new VM or from Template - # Only create virtual device if not backed by vmdk in original template - if diskspec.device.backing.fileName == '': - diskspec.fileOperation = vim.vm.device.VirtualDeviceSpec.FileOperation.create - - # which datastore? - if expected_disk_spec.get('datastore'): - # TODO: This is already handled by the relocation spec, - # but it needs to eventually be handled for all the - # other disks defined - pass - - kb = self.get_configured_disk_size(expected_disk_spec) - # VMware doesn't allow to reduce disk sizes - if kb < diskspec.device.capacityInKB: - self.module.fail_json( - msg="Given disk size is smaller than found (%d < %d). Reducing disks is not allowed." % - (kb, diskspec.device.capacityInKB)) - - if kb != diskspec.device.capacityInKB or disk_modified: - diskspec.device.capacityInKB = kb - self.configspec.deviceChange.append(diskspec) - - self.change_detected = True - - def select_host(self): - hostsystem = self.cache.get_esx_host(self.params['esxi_hostname']) - if not hostsystem: - self.module.fail_json(msg='Failed to find ESX host "%(esxi_hostname)s"' % self.params) - if hostsystem.runtime.connectionState != 'connected' or hostsystem.runtime.inMaintenanceMode: - self.module.fail_json(msg='ESXi "%(esxi_hostname)s" is in invalid state or in maintenance mode.' % self.params) - return hostsystem - - def autoselect_datastore(self): - datastore = None - datastores = self.cache.get_all_objs(self.content, [vim.Datastore]) - - if datastores is None or len(datastores) == 0: - self.module.fail_json(msg="Unable to find a datastore list when autoselecting") - - datastore_freespace = 0 - for ds in datastores: - if not self.is_datastore_valid(datastore_obj=ds): - continue - - if ds.summary.freeSpace > datastore_freespace: - datastore = ds - datastore_freespace = ds.summary.freeSpace - - return datastore - - def get_recommended_datastore(self, datastore_cluster_obj=None): - """ - Function to return Storage DRS recommended datastore from datastore cluster - Args: - datastore_cluster_obj: datastore cluster managed object - - Returns: Name of recommended datastore from the given datastore cluster - - """ - if datastore_cluster_obj is None: - return None - # Check if Datastore Cluster provided by user is SDRS ready - sdrs_status = datastore_cluster_obj.podStorageDrsEntry.storageDrsConfig.podConfig.enabled - if sdrs_status: - # We can get storage recommendation only if SDRS is enabled on given datastorage cluster - pod_sel_spec = vim.storageDrs.PodSelectionSpec() - pod_sel_spec.storagePod = datastore_cluster_obj - storage_spec = vim.storageDrs.StoragePlacementSpec() - storage_spec.podSelectionSpec = pod_sel_spec - storage_spec.type = 'create' - - try: - rec = self.content.storageResourceManager.RecommendDatastores(storageSpec=storage_spec) - rec_action = rec.recommendations[0].action[0] - return rec_action.destination.name - except Exception: - # There is some error so we fall back to general workflow - pass - datastore = None - datastore_freespace = 0 - for ds in datastore_cluster_obj.childEntity: - if isinstance(ds, vim.Datastore) and ds.summary.freeSpace > datastore_freespace: - # If datastore field is provided, filter destination datastores - if not self.is_datastore_valid(datastore_obj=ds): - continue - - datastore = ds - datastore_freespace = ds.summary.freeSpace - if datastore: - return datastore.name - return None - - def select_datastore(self, vm_obj=None): - datastore = None - datastore_name = None - - if len(self.params['disk']) != 0: - # TODO: really use the datastore for newly created disks - if 'autoselect_datastore' in self.params['disk'][0] and self.params['disk'][0]['autoselect_datastore']: - datastores = [] - - if self.params['cluster']: - cluster = self.find_cluster_by_name(self.params['cluster'], self.content) - - for host in cluster.host: - for mi in host.configManager.storageSystem.fileSystemVolumeInfo.mountInfo: - if mi.volume.type == "VMFS": - datastores.append(self.cache.find_obj(self.content, [vim.Datastore], mi.volume.name)) - elif self.params['esxi_hostname']: - host = self.find_hostsystem_by_name(self.params['esxi_hostname']) - - for mi in host.configManager.storageSystem.fileSystemVolumeInfo.mountInfo: - if mi.volume.type == "VMFS": - datastores.append(self.cache.find_obj(self.content, [vim.Datastore], mi.volume.name)) - else: - datastores = self.cache.get_all_objs(self.content, [vim.Datastore]) - datastores = [x for x in datastores if self.cache.get_parent_datacenter(x).name == self.params['datacenter']] - - datastore_freespace = 0 - for ds in datastores: - if not self.is_datastore_valid(datastore_obj=ds): - continue - - if (ds.summary.freeSpace > datastore_freespace) or (ds.summary.freeSpace == datastore_freespace and not datastore): - # If datastore field is provided, filter destination datastores - if 'datastore' in self.params['disk'][0] and \ - isinstance(self.params['disk'][0]['datastore'], str) and \ - ds.name.find(self.params['disk'][0]['datastore']) < 0: - continue - - datastore = ds - datastore_name = datastore.name - datastore_freespace = ds.summary.freeSpace - - elif 'datastore' in self.params['disk'][0]: - datastore_name = self.params['disk'][0]['datastore'] - # Check if user has provided datastore cluster first - datastore_cluster = self.cache.find_obj(self.content, [vim.StoragePod], datastore_name) - if datastore_cluster: - # If user specified datastore cluster so get recommended datastore - datastore_name = self.get_recommended_datastore(datastore_cluster_obj=datastore_cluster) - # Check if get_recommended_datastore or user specified datastore exists or not - datastore = self.cache.find_obj(self.content, [vim.Datastore], datastore_name) - else: - self.module.fail_json(msg="Either datastore or autoselect_datastore should be provided to select datastore") - - if not datastore and self.params['template']: - # use the template's existing DS - disks = [x for x in vm_obj.config.hardware.device if isinstance(x, vim.vm.device.VirtualDisk)] - if disks: - datastore = disks[0].backing.datastore - datastore_name = datastore.name - # validation - if datastore: - dc = self.cache.get_parent_datacenter(datastore) - if dc.name != self.params['datacenter']: - datastore = self.autoselect_datastore() - datastore_name = datastore.name - - if not datastore: - if len(self.params['disk']) != 0 or self.params['template'] is None: - self.module.fail_json(msg="Unable to find the datastore with given parameters." - " This could mean, %s is a non-existent virtual machine and module tried to" - " deploy it as new virtual machine with no disk. Please specify disks parameter" - " or specify template to clone from." % self.params['name']) - self.module.fail_json(msg="Failed to find a matching datastore") - - return datastore, datastore_name - - def obj_has_parent(self, obj, parent): - if obj is None and parent is None: - raise AssertionError() - current_parent = obj - - while True: - if current_parent.name == parent.name: - return True - - # Check if we have reached till root folder - moid = current_parent._moId - if moid in ['group-d1', 'ha-folder-root']: - return False - - current_parent = current_parent.parent - if current_parent is None: - return False - - def get_scsi_type(self): - disk_controller_type = "paravirtual" - # set cpu/memory/etc - if 'hardware' in self.params: - if 'scsi' in self.params['hardware']: - if self.params['hardware']['scsi'] in ['buslogic', 'paravirtual', 'lsilogic', 'lsilogicsas']: - disk_controller_type = self.params['hardware']['scsi'] - else: - self.module.fail_json(msg="hardware.scsi attribute should be 'paravirtual' or 'lsilogic'") - return disk_controller_type - - def find_folder(self, searchpath): - """ Walk inventory objects one position of the searchpath at a time """ - - # split the searchpath so we can iterate through it - paths = [x.replace('/', '') for x in searchpath.split('/')] - paths_total = len(paths) - 1 - position = 0 - - # recursive walk while looking for next element in searchpath - root = self.content.rootFolder - while root and position <= paths_total: - change = False - if hasattr(root, 'childEntity'): - for child in root.childEntity: - if child.name == paths[position]: - root = child - position += 1 - change = True - break - elif isinstance(root, vim.Datacenter): - if hasattr(root, 'vmFolder'): - if root.vmFolder.name == paths[position]: - root = root.vmFolder - position += 1 - change = True - else: - root = None - - if not change: - root = None - - return root - - def get_resource_pool(self, cluster=None, host=None, resource_pool=None): - """ Get a resource pool, filter on cluster, esxi_hostname or resource_pool if given """ - - cluster_name = cluster or self.params.get('cluster', None) - host_name = host or self.params.get('esxi_hostname', None) - resource_pool_name = resource_pool or self.params.get('resource_pool', None) - - # get the datacenter object - datacenter = find_obj(self.content, [vim.Datacenter], self.params['datacenter']) - if not datacenter: - self.module.fail_json(msg='Unable to find datacenter "%s"' % self.params['datacenter']) - - # if cluster is given, get the cluster object - if cluster_name: - cluster = find_obj(self.content, [vim.ComputeResource], cluster_name, folder=datacenter) - if not cluster: - self.module.fail_json(msg='Unable to find cluster "%s"' % cluster_name) - # if host is given, get the cluster object using the host - elif host_name: - host = find_obj(self.content, [vim.HostSystem], host_name, folder=datacenter) - if not host: - self.module.fail_json(msg='Unable to find host "%s"' % host_name) - cluster = host.parent - else: - cluster = None - - # get resource pools limiting search to cluster or datacenter - resource_pool = find_obj(self.content, [vim.ResourcePool], resource_pool_name, folder=cluster or datacenter) - if not resource_pool: - if resource_pool_name: - self.module.fail_json(msg='Unable to find resource_pool "%s"' % resource_pool_name) - else: - self.module.fail_json(msg='Unable to find resource pool, need esxi_hostname, resource_pool, or cluster') - return resource_pool - - def deploy_vm(self): - # https://github.com/vmware/pyvmomi-community-samples/blob/master/samples/clone_vm.py - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.CloneSpec.html - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.vm.ConfigSpec.html - # https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html - - # FIXME: - # - static IPs - - self.folder = self.params.get('folder', None) - if self.folder is None: - self.module.fail_json(msg="Folder is required parameter while deploying new virtual machine") - - # Prepend / if it was missing from the folder path, also strip trailing slashes - if not self.folder.startswith('/'): - self.folder = '/%(folder)s' % self.params - self.folder = self.folder.rstrip('/') - - datacenter = self.cache.find_obj(self.content, [vim.Datacenter], self.params['datacenter']) - if datacenter is None: - self.module.fail_json(msg='No datacenter named %(datacenter)s was found' % self.params) - - dcpath = compile_folder_path_for_object(datacenter) - - # Nested folder does not have trailing / - if not dcpath.endswith('/'): - dcpath += '/' - - # Check for full path first in case it was already supplied - if (self.folder.startswith(dcpath + self.params['datacenter'] + '/vm') or - self.folder.startswith(dcpath + '/' + self.params['datacenter'] + '/vm')): - fullpath = self.folder - elif self.folder.startswith('/vm/') or self.folder == '/vm': - fullpath = "%s%s%s" % (dcpath, self.params['datacenter'], self.folder) - elif self.folder.startswith('/'): - fullpath = "%s%s/vm%s" % (dcpath, self.params['datacenter'], self.folder) - else: - fullpath = "%s%s/vm/%s" % (dcpath, self.params['datacenter'], self.folder) - - f_obj = self.content.searchIndex.FindByInventoryPath(fullpath) - - # abort if no strategy was successful - if f_obj is None: - # Add some debugging values in failure. - details = { - 'datacenter': datacenter.name, - 'datacenter_path': dcpath, - 'folder': self.folder, - 'full_search_path': fullpath, - } - self.module.fail_json(msg='No folder %s matched in the search path : %s' % (self.folder, fullpath), - details=details) - - destfolder = f_obj - - if self.params['template']: - vm_obj = self.get_vm_or_template(template_name=self.params['template']) - if vm_obj is None: - self.module.fail_json(msg="Could not find a template named %(template)s" % self.params) - else: - vm_obj = None - - # always get a resource_pool - resource_pool = self.get_resource_pool() - - # set the destination datastore for VM & disks - if self.params['datastore']: - # Give precedence to datastore value provided by user - # User may want to deploy VM to specific datastore. - datastore_name = self.params['datastore'] - # Check if user has provided datastore cluster first - datastore_cluster = self.cache.find_obj(self.content, [vim.StoragePod], datastore_name) - if datastore_cluster: - # If user specified datastore cluster so get recommended datastore - datastore_name = self.get_recommended_datastore(datastore_cluster_obj=datastore_cluster) - # Check if get_recommended_datastore or user specified datastore exists or not - datastore = self.cache.find_obj(self.content, [vim.Datastore], datastore_name) - else: - (datastore, datastore_name) = self.select_datastore(vm_obj) - - self.configspec = vim.vm.ConfigSpec() - self.configspec.deviceChange = [] - # create the relocation spec - self.relospec = vim.vm.RelocateSpec() - self.relospec.deviceChange = [] - self.configure_guestid(vm_obj=vm_obj, vm_creation=True) - self.configure_cpu_and_memory(vm_obj=vm_obj, vm_creation=True) - self.configure_hardware_params(vm_obj=vm_obj) - self.configure_resource_alloc_info(vm_obj=vm_obj) - self.configure_vapp_properties(vm_obj=vm_obj) - self.configure_disks(vm_obj=vm_obj) - self.configure_network(vm_obj=vm_obj) - self.configure_cdrom(vm_obj=vm_obj) - - # Find if we need network customizations (find keys in dictionary that requires customizations) - network_changes = False - for nw in self.params['networks']: - for key in nw: - # We don't need customizations for these keys - if key == 'type' and nw['type'] == 'dhcp': - network_changes = True - break - if key not in ('device_type', 'mac', 'name', 'vlan', 'type', 'start_connected', 'dvswitch_name'): - network_changes = True - break - - if len(self.params['customization']) > 0 or network_changes or self.params.get('customization_spec') is not None: - self.customize_vm(vm_obj=vm_obj) - - clonespec = None - clone_method = None - try: - if self.params['template']: - # Only select specific host when ESXi hostname is provided - if self.params['esxi_hostname']: - self.relospec.host = self.select_host() - self.relospec.datastore = datastore - - # Convert disk present in template if is set - if self.params['convert']: - for device in vm_obj.config.hardware.device: - if isinstance(device, vim.vm.device.VirtualDisk): - disk_locator = vim.vm.RelocateSpec.DiskLocator() - disk_locator.diskBackingInfo = vim.vm.device.VirtualDisk.FlatVer2BackingInfo() - if self.params['convert'] in ['thin']: - disk_locator.diskBackingInfo.thinProvisioned = True - if self.params['convert'] in ['eagerzeroedthick']: - disk_locator.diskBackingInfo.eagerlyScrub = True - if self.params['convert'] in ['thick']: - disk_locator.diskBackingInfo.diskMode = "persistent" - disk_locator.diskId = device.key - disk_locator.datastore = datastore - self.relospec.disk.append(disk_locator) - - # https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.vm.RelocateSpec.html - # > pool: For a clone operation from a template to a virtual machine, this argument is required. - self.relospec.pool = resource_pool - linked_clone = self.params.get('linked_clone') - snapshot_src = self.params.get('snapshot_src', None) - if linked_clone: - if snapshot_src is not None: - self.relospec.diskMoveType = vim.vm.RelocateSpec.DiskMoveOptions.createNewChildDiskBacking - else: - self.module.fail_json(msg="Parameter 'linked_src' and 'snapshot_src' are" - " required together for linked clone operation.") - - clonespec = vim.vm.CloneSpec(template=self.params['is_template'], location=self.relospec) - if self.customspec: - clonespec.customization = self.customspec - - if snapshot_src is not None: - if vm_obj.snapshot is None: - self.module.fail_json(msg="No snapshots present for virtual machine or template [%(template)s]" % self.params) - snapshot = self.get_snapshots_by_name_recursively(snapshots=vm_obj.snapshot.rootSnapshotList, - snapname=snapshot_src) - if len(snapshot) != 1: - self.module.fail_json(msg='virtual machine "%(template)s" does not contain' - ' snapshot named "%(snapshot_src)s"' % self.params) - - clonespec.snapshot = snapshot[0].snapshot - - clonespec.config = self.configspec - clone_method = 'Clone' - try: - task = vm_obj.Clone(folder=destfolder, name=self.params['name'], spec=clonespec) - except vim.fault.NoPermission as e: - self.module.fail_json(msg="Failed to clone virtual machine %s to folder %s " - "due to permission issue: %s" % (self.params['name'], - destfolder, - to_native(e.msg))) - self.change_detected = True - else: - # ConfigSpec require name for VM creation - self.configspec.name = self.params['name'] - self.configspec.files = vim.vm.FileInfo(logDirectory=None, - snapshotDirectory=None, - suspendDirectory=None, - vmPathName="[" + datastore_name + "]") - - clone_method = 'CreateVM_Task' - try: - task = destfolder.CreateVM_Task(config=self.configspec, pool=resource_pool) - except vmodl.fault.InvalidRequest as e: - self.module.fail_json(msg="Failed to create virtual machine due to invalid configuration " - "parameter %s" % to_native(e.msg)) - except vim.fault.RestrictedVersion as e: - self.module.fail_json(msg="Failed to create virtual machine due to " - "product versioning restrictions: %s" % to_native(e.msg)) - self.change_detected = True - self.wait_for_task(task) - except TypeError as e: - self.module.fail_json(msg="TypeError was returned, please ensure to give correct inputs. %s" % to_text(e)) - - if task.info.state == 'error': - # https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2021361 - # https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2173 - - # provide these to the user for debugging - clonespec_json = serialize_spec(clonespec) - configspec_json = serialize_spec(self.configspec) - kwargs = { - 'changed': self.change_applied, - 'failed': True, - 'msg': task.info.error.msg, - 'clonespec': clonespec_json, - 'configspec': configspec_json, - 'clone_method': clone_method - } - - return kwargs - else: - # set annotation - vm = task.info.result - if self.params['annotation']: - annotation_spec = vim.vm.ConfigSpec() - annotation_spec.annotation = str(self.params['annotation']) - task = vm.ReconfigVM_Task(annotation_spec) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'annotation'} - - if self.params['customvalues']: - vm_custom_spec = vim.vm.ConfigSpec() - self.customize_customvalues(vm_obj=vm, config_spec=vm_custom_spec) - task = vm.ReconfigVM_Task(vm_custom_spec) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'customvalues'} - - if self.params['wait_for_ip_address'] or self.params['wait_for_customization'] or self.params['state'] in ['poweredon', 'restarted']: - set_vm_power_state(self.content, vm, 'poweredon', force=False) - - if self.params['wait_for_ip_address']: - wait_for_vm_ip(self.content, vm, self.params['wait_for_ip_address_timeout']) - - if self.params['wait_for_customization']: - is_customization_ok = self.wait_for_customization(vm=vm, timeout=self.params['wait_for_customization_timeout']) - if not is_customization_ok: - vm_facts = self.gather_facts(vm) - return {'changed': self.change_applied, 'failed': True, 'instance': vm_facts, 'op': 'customization'} - - vm_facts = self.gather_facts(vm) - return {'changed': self.change_applied, 'failed': False, 'instance': vm_facts} - - def get_snapshots_by_name_recursively(self, snapshots, snapname): - snap_obj = [] - for snapshot in snapshots: - if snapshot.name == snapname: - snap_obj.append(snapshot) - else: - snap_obj = snap_obj + self.get_snapshots_by_name_recursively(snapshot.childSnapshotList, snapname) - return snap_obj - - def reconfigure_vm(self): - self.configspec = vim.vm.ConfigSpec() - self.configspec.deviceChange = [] - # create the relocation spec - self.relospec = vim.vm.RelocateSpec() - self.relospec.deviceChange = [] - self.configure_guestid(vm_obj=self.current_vm_obj) - self.configure_cpu_and_memory(vm_obj=self.current_vm_obj) - self.configure_hardware_params(vm_obj=self.current_vm_obj) - self.configure_disks(vm_obj=self.current_vm_obj) - self.configure_network(vm_obj=self.current_vm_obj) - self.configure_cdrom(vm_obj=self.current_vm_obj) - self.customize_customvalues(vm_obj=self.current_vm_obj, config_spec=self.configspec) - self.configure_resource_alloc_info(vm_obj=self.current_vm_obj) - self.configure_vapp_properties(vm_obj=self.current_vm_obj) - - if self.params['annotation'] and self.current_vm_obj.config.annotation != self.params['annotation']: - self.configspec.annotation = str(self.params['annotation']) - self.change_detected = True - - if self.params['resource_pool']: - self.relospec.pool = self.get_resource_pool() - - if self.relospec.pool != self.current_vm_obj.resourcePool: - task = self.current_vm_obj.RelocateVM_Task(spec=self.relospec) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'relocate'} - - # Only send VMware task if we see a modification - if self.change_detected: - task = None - try: - task = self.current_vm_obj.ReconfigVM_Task(spec=self.configspec) - except vim.fault.RestrictedVersion as e: - self.module.fail_json(msg="Failed to reconfigure virtual machine due to" - " product versioning restrictions: %s" % to_native(e.msg)) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'reconfig'} - - # Rename VM - if self.params['uuid'] and self.params['name'] and self.params['name'] != self.current_vm_obj.config.name: - task = self.current_vm_obj.Rename_Task(self.params['name']) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'rename'} - - # Mark VM as Template - if self.params['is_template'] and not self.current_vm_obj.config.template: - try: - self.current_vm_obj.MarkAsTemplate() - self.change_applied = True - except vmodl.fault.NotSupported as e: - self.module.fail_json(msg="Failed to mark virtual machine [%s] " - "as template: %s" % (self.params['name'], e.msg)) - - # Mark Template as VM - elif not self.params['is_template'] and self.current_vm_obj.config.template: - resource_pool = self.get_resource_pool() - kwargs = dict(pool=resource_pool) - - if self.params.get('esxi_hostname', None): - host_system_obj = self.select_host() - kwargs.update(host=host_system_obj) - - try: - self.current_vm_obj.MarkAsVirtualMachine(**kwargs) - self.change_applied = True - except vim.fault.InvalidState as invalid_state: - self.module.fail_json(msg="Virtual machine is not marked" - " as template : %s" % to_native(invalid_state.msg)) - except vim.fault.InvalidDatastore as invalid_ds: - self.module.fail_json(msg="Converting template to virtual machine" - " operation cannot be performed on the" - " target datastores: %s" % to_native(invalid_ds.msg)) - except vim.fault.CannotAccessVmComponent as cannot_access: - self.module.fail_json(msg="Failed to convert template to virtual machine" - " as operation unable access virtual machine" - " component: %s" % to_native(cannot_access.msg)) - except vmodl.fault.InvalidArgument as invalid_argument: - self.module.fail_json(msg="Failed to convert template to virtual machine" - " due to : %s" % to_native(invalid_argument.msg)) - except Exception as generic_exc: - self.module.fail_json(msg="Failed to convert template to virtual machine" - " due to generic error : %s" % to_native(generic_exc)) - - # Automatically update VMware UUID when converting template to VM. - # This avoids an interactive prompt during VM startup. - uuid_action = [x for x in self.current_vm_obj.config.extraConfig if x.key == "uuid.action"] - if not uuid_action: - uuid_action_opt = vim.option.OptionValue() - uuid_action_opt.key = "uuid.action" - uuid_action_opt.value = "create" - self.configspec.extraConfig.append(uuid_action_opt) - - self.change_detected = True - - # add customize existing VM after VM re-configure - if 'existing_vm' in self.params['customization'] and self.params['customization']['existing_vm']: - if self.current_vm_obj.config.template: - self.module.fail_json(msg="VM is template, not support guest OS customization.") - if self.current_vm_obj.runtime.powerState != vim.VirtualMachinePowerState.poweredOff: - self.module.fail_json(msg="VM is not in poweroff state, can not do guest OS customization.") - cus_result = self.customize_exist_vm() - if cus_result['failed']: - return cus_result - - vm_facts = self.gather_facts(self.current_vm_obj) - return {'changed': self.change_applied, 'failed': False, 'instance': vm_facts} - - def customize_exist_vm(self): - task = None - # Find if we need network customizations (find keys in dictionary that requires customizations) - network_changes = False - for nw in self.params['networks']: - for key in nw: - # We don't need customizations for these keys - if key not in ('device_type', 'mac', 'name', 'vlan', 'type', 'start_connected', 'dvswitch_name'): - network_changes = True - break - if len(self.params['customization']) > 1 or network_changes or self.params.get('customization_spec'): - self.customize_vm(vm_obj=self.current_vm_obj) - try: - task = self.current_vm_obj.CustomizeVM_Task(self.customspec) - except vim.fault.CustomizationFault as e: - self.module.fail_json(msg="Failed to customization virtual machine due to CustomizationFault: %s" % to_native(e.msg)) - except vim.fault.RuntimeFault as e: - self.module.fail_json(msg="failed to customization virtual machine due to RuntimeFault: %s" % to_native(e.msg)) - except Exception as e: - self.module.fail_json(msg="failed to customization virtual machine due to fault: %s" % to_native(e.msg)) - self.wait_for_task(task) - if task.info.state == 'error': - return {'changed': self.change_applied, 'failed': True, 'msg': task.info.error.msg, 'op': 'customize_exist'} - - if self.params['wait_for_customization']: - set_vm_power_state(self.content, self.current_vm_obj, 'poweredon', force=False) - is_customization_ok = self.wait_for_customization(vm=self.current_vm_obj, timeout=self.params['wait_for_customization_timeout']) - if not is_customization_ok: - return {'changed': self.change_applied, 'failed': True, - 'msg': 'Wait for customization failed due to timeout', 'op': 'wait_for_customize_exist'} - - return {'changed': self.change_applied, 'failed': False} - - def wait_for_task(self, task, poll_interval=1): - """ - Wait for a VMware task to complete. Terminal states are 'error' and 'success'. - - Inputs: - - task: the task to wait for - - poll_interval: polling interval to check the task, in seconds - - Modifies: - - self.change_applied - """ - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.Task.html - # https://www.vmware.com/support/developer/vc-sdk/visdk25pubs/ReferenceGuide/vim.TaskInfo.html - # https://github.com/virtdevninja/pyvmomi-community-samples/blob/master/samples/tools/tasks.py - while task.info.state not in ['error', 'success']: - time.sleep(poll_interval) - self.change_applied = self.change_applied or task.info.state == 'success' - - def get_vm_events(self, vm, eventTypeIdList): - byEntity = vim.event.EventFilterSpec.ByEntity(entity=vm, recursion="self") - filterSpec = vim.event.EventFilterSpec(entity=byEntity, eventTypeId=eventTypeIdList) - eventManager = self.content.eventManager - return eventManager.QueryEvent(filterSpec) - - def wait_for_customization(self, vm, timeout=3600, sleep=10): - poll = int(timeout // sleep) - thispoll = 0 - while thispoll <= poll: - eventStarted = self.get_vm_events(vm, ['CustomizationStartedEvent']) - if len(eventStarted): - thispoll = 0 - while thispoll <= poll: - eventsFinishedResult = self.get_vm_events(vm, ['CustomizationSucceeded', 'CustomizationFailed']) - if len(eventsFinishedResult): - if not isinstance(eventsFinishedResult[0], vim.event.CustomizationSucceeded): - self.module.warn("Customization failed with error {%s}:{%s}" - % (eventsFinishedResult[0]._wsdlName, eventsFinishedResult[0].fullFormattedMessage)) - return False - else: - return True - else: - time.sleep(sleep) - thispoll += 1 - if len(eventsFinishedResult) == 0: - self.module.warn('Waiting for customization result event timed out.') - return False - else: - time.sleep(sleep) - thispoll += 1 - if len(eventStarted): - self.module.warn('Waiting for customization result event timed out.') - else: - self.module.warn('Waiting for customization start event timed out.') - return False - - -def main(): - argument_spec = vmware_argument_spec() - argument_spec.update( - state=dict(type='str', default='present', - choices=['absent', 'poweredoff', 'poweredon', 'present', 'rebootguest', 'restarted', 'shutdownguest', 'suspended']), - template=dict(type='str', aliases=['template_src']), - is_template=dict(type='bool', default=False), - annotation=dict(type='str', aliases=['notes']), - customvalues=dict(type='list', default=[]), - name=dict(type='str'), - name_match=dict(type='str', choices=['first', 'last'], default='first'), - uuid=dict(type='str'), - use_instance_uuid=dict(type='bool', default=False), - folder=dict(type='str'), - guest_id=dict(type='str'), - disk=dict(type='list', default=[]), - cdrom=dict(type=list_or_dict, default=[]), - hardware=dict(type='dict', default={}), - force=dict(type='bool', default=False), - datacenter=dict(type='str', default='ha-datacenter'), - esxi_hostname=dict(type='str'), - cluster=dict(type='str'), - wait_for_ip_address=dict(type='bool', default=False), - wait_for_ip_address_timeout=dict(type='int', default=300), - state_change_timeout=dict(type='int', default=0), - snapshot_src=dict(type='str'), - linked_clone=dict(type='bool', default=False), - networks=dict(type='list', default=[]), - resource_pool=dict(type='str'), - customization=dict(type='dict', default={}, no_log=True), - customization_spec=dict(type='str', default=None), - wait_for_customization=dict(type='bool', default=False), - wait_for_customization_timeout=dict(type='int', default=3600), - vapp_properties=dict(type='list', default=[]), - datastore=dict(type='str'), - convert=dict(type='str', choices=['thin', 'thick', 'eagerzeroedthick']), - delete_from_inventory=dict(type='bool', default=False), - ) - - module = AnsibleModule(argument_spec=argument_spec, - supports_check_mode=True, - mutually_exclusive=[ - ['cluster', 'esxi_hostname'], - ], - required_one_of=[ - ['name', 'uuid'], - ], - ) - - result = {'failed': False, 'changed': False} - - pyv = PyVmomiHelper(module) - - # Check if the VM exists before continuing - vm = pyv.get_vm() - - # VM already exists - if vm: - if module.params['state'] == 'absent': - # destroy it - if module.check_mode: - result.update( - vm_name=vm.name, - changed=True, - current_powerstate=vm.summary.runtime.powerState.lower(), - desired_operation='remove_vm', - ) - module.exit_json(**result) - if module.params['force']: - # has to be poweredoff first - set_vm_power_state(pyv.content, vm, 'poweredoff', module.params['force']) - result = pyv.remove_vm(vm, module.params['delete_from_inventory']) - elif module.params['state'] == 'present': - if module.check_mode: - result.update( - vm_name=vm.name, - changed=True, - desired_operation='reconfigure_vm', - ) - module.exit_json(**result) - result = pyv.reconfigure_vm() - elif module.params['state'] in ['poweredon', 'poweredoff', 'restarted', 'suspended', 'shutdownguest', 'rebootguest']: - if module.check_mode: - result.update( - vm_name=vm.name, - changed=True, - current_powerstate=vm.summary.runtime.powerState.lower(), - desired_operation='set_vm_power_state', - ) - module.exit_json(**result) - # set powerstate - tmp_result = set_vm_power_state(pyv.content, vm, module.params['state'], module.params['force'], module.params['state_change_timeout']) - if tmp_result['changed']: - result["changed"] = True - if module.params['state'] in ['poweredon', 'restarted', 'rebootguest'] and module.params['wait_for_ip_address']: - wait_result = wait_for_vm_ip(pyv.content, vm, module.params['wait_for_ip_address_timeout']) - if not wait_result: - module.fail_json(msg='Waiting for IP address timed out') - tmp_result['instance'] = wait_result - if not tmp_result["failed"]: - result["failed"] = False - result['instance'] = tmp_result['instance'] - if tmp_result["failed"]: - result["failed"] = True - result["msg"] = tmp_result["msg"] - else: - # This should not happen - raise AssertionError() - # VM doesn't exist - else: - if module.params['state'] in ['poweredon', 'poweredoff', 'present', 'restarted', 'suspended']: - if module.check_mode: - result.update( - changed=True, - desired_operation='deploy_vm', - ) - module.exit_json(**result) - result = pyv.deploy_vm() - if result['failed']: - module.fail_json(msg='Failed to create a virtual machine : %s' % result['msg']) - - if result['failed']: - module.fail_json(**result) - else: - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/test/support/integration/plugins/modules/vmware_host_hyperthreading.py b/test/support/integration/plugins/modules/vmware_host_hyperthreading.py deleted file mode 100644 index ad579e1e5eb..00000000000 --- a/test/support/integration/plugins/modules/vmware_host_hyperthreading.py +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2018, Christian Kotte -# -# 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 = r''' ---- -module: vmware_host_hyperthreading -short_description: Enables/Disables Hyperthreading optimization for an ESXi host system -description: -- This module can be used to enable or disable Hyperthreading optimization for ESXi host systems in given vCenter infrastructure. -- It also checks if Hyperthreading is activated/deactivated and if the host needs to be restarted. -- The module informs the user if Hyperthreading is enabled but inactive because the processor is vulnerable to L1 Terminal Fault (L1TF). -version_added: 2.8 -author: -- Christian Kotte (@ckotte) -notes: -- Tested on vSphere 6.5 -requirements: -- python >= 2.6 -- PyVmomi -options: - state: - description: - - Enable or disable Hyperthreading. - - You need to reboot the ESXi host if you change the configuration. - - Make sure that Hyperthreading is enabled in the BIOS. Otherwise, it will be enabled, but never activated. - type: str - choices: [ enabled, disabled ] - default: 'enabled' - esxi_hostname: - description: - - Name of the host system to work with. - - This parameter is required if C(cluster_name) is not specified. - type: str - cluster_name: - description: - - Name of the cluster from which all host systems will be used. - - This parameter is required if C(esxi_hostname) is not specified. - type: str -extends_documentation_fragment: vmware.documentation -''' - -EXAMPLES = r''' -- name: Enable Hyperthreading for an host system - vmware_host_hyperthreading: - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - esxi_hostname: '{{ esxi_hostname }}' - state: enabled - validate_certs: no - delegate_to: localhost - -- name: Disable Hyperthreading for an host system - vmware_host_hyperthreading: - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - esxi_hostname: '{{ esxi_hostname }}' - state: disabled - validate_certs: no - delegate_to: localhost - -- name: Disable Hyperthreading for all host systems from cluster - vmware_host_hyperthreading: - hostname: '{{ vcenter_hostname }}' - username: '{{ vcenter_username }}' - password: '{{ vcenter_password }}' - cluster_name: '{{ cluster_name }}' - state: disabled - validate_certs: no - delegate_to: localhost -''' - -RETURN = r''' -results: - description: metadata about host system's Hyperthreading configuration - returned: always - type: dict - sample: { - "esxi01": { - "msg": "Hyperthreading is already enabled and active for host 'esxi01'", - "state_current": "active", - "state": "enabled", - }, - } -''' - -try: - from pyVmomi import vim, vmodl -except ImportError: - pass - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec -from ansible.module_utils._text import to_native - - -class VmwareHostHyperthreading(PyVmomi): - """Manage Hyperthreading for an ESXi host system""" - def __init__(self, module): - super(VmwareHostHyperthreading, self).__init__(module) - cluster_name = self.params.get('cluster_name') - esxi_host_name = self.params.get('esxi_hostname') - self.hosts = self.get_all_host_objs(cluster_name=cluster_name, esxi_host_name=esxi_host_name) - if not self.hosts: - self.module.fail_json(msg="Failed to find host system.") - - def ensure(self): - """Manage Hyperthreading for an ESXi host system""" - results = dict(changed=False, result=dict()) - desired_state = self.params.get('state') - host_change_list = [] - for host in self.hosts: - changed = False - results['result'][host.name] = dict(msg='') - - hyperthreading_info = host.config.hyperThread - - results['result'][host.name]['state'] = desired_state - if desired_state == 'enabled': - # Don't do anything if Hyperthreading is already enabled - if hyperthreading_info.config: - if hyperthreading_info.active: - results['result'][host.name]['changed'] = False - results['result'][host.name]['state_current'] = "active" - results['result'][host.name]['msg'] = "Hyperthreading is enabled and active" - if not hyperthreading_info.active: - # L1 Terminal Fault (L1TF)/Foreshadow mitigation workaround (https://kb.vmware.com/s/article/55806) - option_manager = host.configManager.advancedOption - try: - mitigation = option_manager.QueryOptions('VMkernel.Boot.hyperthreadingMitigation') - except vim.fault.InvalidName: - mitigation = None - if mitigation and mitigation[0].value: - results['result'][host.name]['changed'] = False - results['result'][host.name]['state_current'] = "enabled" - results['result'][host.name]['msg'] = ("Hyperthreading is enabled, but not active because the" - " processor is vulnerable to L1 Terminal Fault (L1TF).") - else: - changed = results['result'][host.name]['changed'] = True - results['result'][host.name]['state_current'] = "enabled" - results['result'][host.name]['msg'] = ("Hyperthreading is enabled, but not active." - " A reboot is required!") - # Enable Hyperthreading - else: - # Check if Hyperthreading is available - if hyperthreading_info.available: - if not self.module.check_mode: - try: - host.configManager.cpuScheduler.EnableHyperThreading() - changed = results['result'][host.name]['changed'] = True - results['result'][host.name]['state_previous'] = "disabled" - results['result'][host.name]['state_current'] = "enabled" - results['result'][host.name]['msg'] = ( - "Hyperthreading enabled for host. Reboot the host to activate it." - ) - except vmodl.fault.NotSupported as not_supported: - # This should never happen since Hyperthreading is available - self.module.fail_json( - msg="Failed to enable Hyperthreading for host '%s' : %s" % - (host.name, to_native(not_supported.msg)) - ) - except (vmodl.RuntimeFault, vmodl.MethodFault) as runtime_fault: - self.module.fail_json( - msg="Failed to enable Hyperthreading for host '%s' due to : %s" % - (host.name, to_native(runtime_fault.msg)) - ) - else: - changed = results['result'][host.name]['changed'] = True - results['result'][host.name]['state_previous'] = "disabled" - results['result'][host.name]['state_current'] = "enabled" - results['result'][host.name]['msg'] = "Hyperthreading will be enabled" - else: - self.module.fail_json(msg="Hyperthreading optimization is not available for host '%s'" % host.name) - elif desired_state == 'disabled': - # Don't do anything if Hyperthreading is already disabled - if not hyperthreading_info.config: - if not hyperthreading_info.active: - results['result'][host.name]['changed'] = False - results['result'][host.name]['state_current'] = "inactive" - results['result'][host.name]['msg'] = "Hyperthreading is disabled and inactive" - if hyperthreading_info.active: - changed = results['result'][host.name]['changed'] = True - results['result'][host.name]['state_current'] = "disabled" - results['result'][host.name]['msg'] = ("Hyperthreading is already disabled" - " but still active. A reboot is required!") - # Disable Hyperthreading - else: - # Check if Hyperthreading is available - if hyperthreading_info.available: - if not self.module.check_mode: - try: - host.configManager.cpuScheduler.DisableHyperThreading() - changed = results['result'][host.name]['changed'] = True - results['result'][host.name]['state_previous'] = "enabled" - results['result'][host.name]['state_current'] = "disabled" - results['result'][host.name]['msg'] = ( - "Hyperthreading disabled. Reboot the host to deactivate it." - ) - except vmodl.fault.NotSupported as not_supported: - # This should never happen since Hyperthreading is available - self.module.fail_json( - msg="Failed to disable Hyperthreading for host '%s' : %s" % - (host.name, to_native(not_supported.msg)) - ) - except (vmodl.RuntimeFault, vmodl.MethodFault) as runtime_fault: - self.module.fail_json( - msg="Failed to disable Hyperthreading for host '%s' due to : %s" % - (host.name, to_native(runtime_fault.msg)) - ) - else: - changed = results['result'][host.name]['changed'] = True - results['result'][host.name]['state_previous'] = "enabled" - results['result'][host.name]['state_current'] = "disabled" - results['result'][host.name]['msg'] = "Hyperthreading will be disabled" - else: - self.module.fail_json(msg="Hyperthreading optimization is not available for host '%s'" % host.name) - - host_change_list.append(changed) - - if any(host_change_list): - results['changed'] = True - self.module.exit_json(**results) - - -def main(): - """Main""" - argument_spec = vmware_argument_spec() - argument_spec.update( - state=dict(default='enabled', choices=['enabled', 'disabled']), - esxi_hostname=dict(type='str', required=False), - cluster_name=dict(type='str', required=False), - ) - - module = AnsibleModule(argument_spec=argument_spec, - required_one_of=[ - ['cluster_name', 'esxi_hostname'], - ], - supports_check_mode=True - ) - - hyperthreading = VmwareHostHyperthreading(module) - hyperthreading.ensure() - - -if __name__ == '__main__': - main()