From 29d3505cb48aeb1a86214eb3b875c718a0ca3238 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Fri, 15 Dec 2017 16:26:19 +0530 Subject: [PATCH] VMware: check for ESXi server while creating user (#33061) This fix check for ESXi server instance before proceeding with managing local user. Also, adds integration tests for this change. Fixes: #32465 Signed-off-by: Abhijeet Kasurde --- lib/ansible/module_utils/vmware.py | 18 +++ .../modules/cloud/vmware/vmware_guest.py | 5 + .../cloud/vmware/vmware_local_user_manager.py | 41 +++--- .../vmware_guest/tasks/poweroff_d1_c1_f0.yml | 2 +- .../vmware_guest/tasks/poweroff_d1_c1_f1.yml | 2 +- .../tasks/poweroff_d1_c1_f0.yml | 2 +- .../tasks/poweroff_d1_c1_f1.yml | 2 +- .../targets/vmware_local_user_manager/aliases | 3 + .../vmware_local_user_manager/tasks/main.yml | 130 ++++++++++++++++++ test/runner/lib/cloud/vcenter.py | 2 +- 10 files changed, 183 insertions(+), 24 deletions(-) create mode 100644 test/integration/targets/vmware_local_user_manager/aliases create mode 100644 test/integration/targets/vmware_local_user_manager/tasks/main.yml diff --git a/lib/ansible/module_utils/vmware.py b/lib/ansible/module_utils/vmware.py index 9241cd7d54e0bb..ddd46a7017a134 100644 --- a/lib/ansible/module_utils/vmware.py +++ b/lib/ansible/module_utils/vmware.py @@ -808,6 +808,24 @@ def __init__(self, module): self.current_vm_obj = None self.content = connect_to_api(self.module) + 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 + # Virtual Machine related functions def get_vm(self): vm = None diff --git a/lib/ansible/modules/cloud/vmware/vmware_guest.py b/lib/ansible/modules/cloud/vmware/vmware_guest.py index 83af724a0ae5cc..673e70d084c282 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_guest.py +++ b/lib/ansible/modules/cloud/vmware/vmware_guest.py @@ -1233,6 +1233,11 @@ def obj_has_parent(self, obj, parent): 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 diff --git a/lib/ansible/modules/cloud/vmware/vmware_local_user_manager.py b/lib/ansible/modules/cloud/vmware/vmware_local_user_manager.py index 4a7ef3196fcdee..caafd94e5938e4 100644 --- a/lib/ansible/modules/cloud/vmware/vmware_local_user_manager.py +++ b/lib/ansible/modules/cloud/vmware/vmware_local_user_manager.py @@ -10,9 +10,11 @@ __metaclass__ = type -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} DOCUMENTATION = ''' @@ -32,15 +34,15 @@ options: local_user_name: description: - - The local user name to be changed + - The local user name to be changed. required: True local_user_password: description: - - The password to be set + - The password to be set. required: False local_user_description: description: - - Description for the user + - Description for the user. required: False state: description: @@ -65,24 +67,28 @@ try: from pyVmomi import vim, vmodl - HAS_PYVMOMI = True except ImportError: - HAS_PYVMOMI = False + pass from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.vmware import HAS_PYVMOMI, connect_to_api, vmware_argument_spec +from ansible.module_utils.vmware import PyVmomi, vmware_argument_spec -class VMwareLocalUserManager(object): +class VMwareLocalUserManager(PyVmomi): def __init__(self, module): - self.module = module - self.content = connect_to_api(self.module) + super(VMwareLocalUserManager, self).__init__(module) self.local_user_name = self.module.params['local_user_name'] self.local_user_password = self.module.params['local_user_password'] self.local_user_description = self.module.params['local_user_description'] self.state = self.module.params['state'] + if self.is_vcenter(): + self.module.fail_json(msg="Failed to get local account manager settings " + "from ESXi server: %s" % self.module.params['hostname'], + details="It seems that %s is a vCenter server instead of an " + "ESXi server" % self.module.params['hostname']) + def process_state(self): try: local_account_manager_states = { @@ -162,17 +168,14 @@ def state_exit_unchanged(self): def main(): - argument_spec = vmware_argument_spec() argument_spec.update(dict(local_user_name=dict(required=True, type='str'), - local_user_password=dict(required=False, type='str', no_log=True), - local_user_description=dict(required=False, type='str'), + local_user_password=dict(type='str', no_log=True), + local_user_description=dict(type='str'), state=dict(default='present', choices=['present', 'absent'], type='str'))) - module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False) - - if not HAS_PYVMOMI: - module.fail_json(msg='pyvmomi is required for this module') + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=False) vmware_local_user_manager = VMwareLocalUserManager(module) vmware_local_user_manager.process_state() diff --git a/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f0.yml b/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f0.yml index 4f0295325f228d..a656d32d67441d 100644 --- a/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f0.yml +++ b/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f0.yml @@ -48,4 +48,4 @@ - name: make sure no changes were made assert: that: - - "poweroff_d1_c1_f0.results|map(attribute='changed')|unique|list == [False]" + - "poweroff_d1_c1_f0.results|map(attribute='changed')|unique|list == [True]" diff --git a/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f1.yml b/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f1.yml index d2c04e3f91b9f1..a3498520c15e39 100644 --- a/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f1.yml +++ b/test/integration/targets/vmware_guest/tasks/poweroff_d1_c1_f1.yml @@ -59,4 +59,4 @@ - name: make sure no changes were made assert: that: - - "poweroff_d1_c1_f1.results|map(attribute='changed')|unique|list == [False]" + - "poweroff_d1_c1_f1.results|map(attribute='changed')|unique|list == [True]" diff --git a/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f0.yml b/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f0.yml index 0c59a1e857f867..192fc5165bf995 100644 --- a/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f0.yml +++ b/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f0.yml @@ -48,4 +48,4 @@ - name: make sure no changes were made assert: that: - - "poweroff_d1_c1_f0.results|map(attribute='changed')|unique|list == [False]" + - "poweroff_d1_c1_f0.results|map(attribute='changed')|unique|list == [True]" diff --git a/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f1.yml b/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f1.yml index 51af09dccd67cb..163ec3951e670e 100644 --- a/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f1.yml +++ b/test/integration/targets/vmware_guest_powerstate/tasks/poweroff_d1_c1_f1.yml @@ -59,4 +59,4 @@ - name: make sure no changes were made assert: that: - - "poweroff_d1_c1_f1.results|map(attribute='changed')|unique|list == [False]" + - "poweroff_d1_c1_f1.results|map(attribute='changed')|unique|list == [True]" diff --git a/test/integration/targets/vmware_local_user_manager/aliases b/test/integration/targets/vmware_local_user_manager/aliases new file mode 100644 index 00000000000000..4c6228bf7a7df2 --- /dev/null +++ b/test/integration/targets/vmware_local_user_manager/aliases @@ -0,0 +1,3 @@ +posix/ci/cloud/group1/vcenter +cloud/vcenter +destructive diff --git a/test/integration/targets/vmware_local_user_manager/tasks/main.yml b/test/integration/targets/vmware_local_user_manager/tasks/main.yml new file mode 100644 index 00000000000000..0e423637fc996a --- /dev/null +++ b/test/integration/targets/vmware_local_user_manager/tasks/main.yml @@ -0,0 +1,130 @@ +# Test code for the vmware_local_user_manager 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: make sure pyvmomi is installed + pip: + name: pyvmomi + state: latest + when: "{{ ansible_user_id == 'root' }}" + +- name: store the vcenter container ip + set_fact: + vcsim: "{{ lookup('env', 'vcenter_host') }}" + +- debug: var=vcsim + +- name: Wait for Flask controller to come up online + wait_for: + host: "{{ vcsim }}" + port: 5000 + state: started + +- name: kill vcsim + uri: + url: http://{{ vcsim }}:5000/killall + +# Local user manager works only with standalone ESXi server +- name: start vcsim + uri: + url: http://{{ vcsim }}:5000/spawn?esx=1 + register: vcsim_instance + +- debug: + var: vcsim_instance + +- name: Wait for vcsim server to come up online + wait_for: + host: "{{ vcsim }}" + port: 443 + state: started + +# Testcase 0001: Add Local user in ESXi server +- name: add local user + vmware_local_user_manager: + hostname: "{{ vcsim }}" + username: "{{ vcsim_instance.json.username }}" + password: "{{ vcsim_instance.json.password }}" + validate_certs: no + local_user_name: testuser_0001 + local_user_password: "SamplePassword!" + state: present + register: user_add_0001 + +- name: ensure user is created + assert: + that: + - user_add_0001.changed == true + +# Testcase 0002: Delete Local user in ESXi server +#- name: Delete local user +# vmware_local_user_manager: +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance.json.username }}" +# password: "{{ vcsim_instance.json.password }}" +# validate_certs: no +# local_user_name: testuser_0001 +# state: absent +# register: user_delete_0002 + +#- name: ensure user is deleted +# assert: +# that: +# - user_delete_0002.changed == true + +#- name: kill vcsim +# uri: +# url: http://{{ vcsim }}:5000/killall + +# Local user manager works only with standalone ESXi server not with vCenter +# So testcase should check failures +#- name: start vcsim +# uri: +# url: http://{{ vcsim }}:5000/spawn?cluster=2 +# register: vcsim_instance + +#- debug: +# var: vcsim_instance + +#- name: Wait for vcsim server to come up online +# wait_for: +# host: "{{ vcsim }}" +# port: 443 +# state: started + +# Testcase 0003: Add Local user in vCenter server +#- name: add local user +# vmware_local_user_manager: +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance.json.username }}" +# password: "{{ vcsim_instance.json.password }}" +# validate_certs: no +# local_user_name: testuser_0003 +# local_user_password: "SamplePassword!" +# state: present +# register: user_add_0003 +# ignore_errors: yes + +#- name: ensure user is created +# assert: +# that: +# - user_add_0003.changed == false +# - "{{ 'Failed to get local account manager settings' in user_add_0003.msg }}" + +## Testcase 0003: Delete Local user in vCenter server +#- name: Delete local user +# vmware_local_user_manager: +# hostname: "{{ vcsim }}" +# username: "{{ vcsim_instance.json.username }}" +# password: "{{ vcsim_instance.json.password }}" +# validate_certs: no +# local_user_name: testuser_0003 +# state: absent +# register: user_delete_0004 +# ignore_errors: yes + +#- name: ensure user is deleted +# assert: +# that: +# - user_delete_0004.changed == false +# - "{{ 'Failed to get local account manager settings' in user_delete_0004.msg }}" diff --git a/test/runner/lib/cloud/vcenter.py b/test/runner/lib/cloud/vcenter.py index 796e8abb5007ed..5eeb3e1c2d13c8 100644 --- a/test/runner/lib/cloud/vcenter.py +++ b/test/runner/lib/cloud/vcenter.py @@ -43,7 +43,7 @@ def __init__(self, args): if os.environ.get('ANSIBLE_VCSIM_CONTAINER'): self.image = os.environ.get('ANSIBLE_VCSIM_CONTAINER') else: - self.image = 'ansible/ansible:vcenter-simulator@sha256:7b7cd213219dc09ae528a8e226804e662c2fae0c1d7d7e2ee3aa9e9c08d4059a' + self.image = 'ansible/ansible:vcenter-simulator@sha256:005faa7442cd164b2a6087b069227fe1979068f420366cc49c57625bcf8f6ebe' self.container_name = '' def filter(self, targets, exclude):