From 254a235ed907cb17441a5eb74c5332eeaf96bc24 Mon Sep 17 00:00:00 2001 From: sky-joker Date: Sun, 23 Aug 2020 20:15:46 +0900 Subject: [PATCH] Fix vmware_guest_serial_port to have idempotency add changelog file update integration test --- .../358-vmware_guest_serial_port.yml | 2 + plugins/modules/vmware_guest_serial_port.py | 95 ++-- .../vmware_guest_serial_port/tasks/main.yml | 487 +++++++++++++++++- 3 files changed, 540 insertions(+), 44 deletions(-) create mode 100644 changelogs/fragments/358-vmware_guest_serial_port.yml diff --git a/changelogs/fragments/358-vmware_guest_serial_port.yml b/changelogs/fragments/358-vmware_guest_serial_port.yml new file mode 100644 index 0000000000..d4eea70261 --- /dev/null +++ b/changelogs/fragments/358-vmware_guest_serial_port.yml @@ -0,0 +1,2 @@ +minor_changes: + - vmware_guest_serial_port - fixed to have idepomtency. diff --git a/plugins/modules/vmware_guest_serial_port.py b/plugins/modules/vmware_guest_serial_port.py index 41c623d53b..dfb00094de 100644 --- a/plugins/modules/vmware_guest_serial_port.py +++ b/plugins/modules/vmware_guest_serial_port.py @@ -52,7 +52,8 @@ - C(absent): remove an existing serial port. C(backing_type) is required to determine the port. The first matching C(backing_type) and either of C(service_uri) or C(pipe_name) or C(device_name) or C(file_path) will be removed. If there is only one device with a backing type, the secondary details are not needed. - We will match the last such device with the given backing type.' + We will match the last such device with the given backing type. + - default: present' - ' - C(yield_on_poll) (bool): Enables CPU yield behavior. Default value is true.' - ' - C(direction) (str): Required when I(backing_type=network). The direction of the connection. @@ -65,12 +66,15 @@ In this case, the host name part of the URI should be empty, or it should specify the address of the local host. If you use the virtual machine as a client, the URI identifies the remote system on the network.' - ' - C(endpoint) (str): Required when I(backing_type=pipe). - When you use serial port pipe backing to connect a virtual machine to another process, you must define the endpoints.' - - ' - C(no_rx_loss) (bool): Required when I(backing_type=pipe). - Enables optimized data transfer over the pipe. + When you use serial port pipe backing to connect a virtual machine to another process, you must define the endpoints. - choices: - client - server' + - ' - C(no_rx_loss) (bool): Required when I(backing_type=pipe). + Enables optimized data transfer over the pipe. + - choices: + - true + - false' - ' - C(pipe_name) (str): Required when I(backing_type=pipe).' - ' - C(device_name) (str): Required when I(backing_type=device).' - ' - C(file_path) (str): Required when I(backing_type=file). @@ -198,30 +202,38 @@ def get_serial_port_config_spec(self, vm_obj): for backing in self.params.get('backings'): backing_keys = backing.keys() serial_port = get_serial_port(vm_obj, backing) - if serial_port is None and 'state' not in backing_keys: - # if serial port is None and state is not mentioned - # create a new serial port - serial_port_spec = self.create_serial_port(backing) - serial_port_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add - self.serial_ports.append(serial_port_spec) - self.change_applied = True - else: - if serial_port is not None and 'state' in backing_keys: - serial_spec = vim.vm.device.VirtualDeviceSpec() - serial_spec.device = serial_port - if backing['state'].lower() == 'present': + if 'state' not in backing_keys: + # state default is to set present if state not in backing_keys + backing.update({'state': 'present'}) + + if 'yield_on_poll' not in backing_keys: + # yield_on_poll default is to set True if yield_on_poll not in backing_keys + backing.update({'yield_on_poll': True}) + + if serial_port: + serial_spec = vim.vm.device.VirtualDeviceSpec() + serial_spec.device = serial_port + if backing['state'] == 'present': + if diff_serial_port_config(serial_port, backing): # modify existing serial port serial_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit serial_spec.device.backing = self.get_backing_info(serial_port, backing, backing['type']) + serial_spec.device.yieldOnPoll = backing['yield_on_poll'] self.change_applied = True self.config_spec.deviceChange.append(serial_spec) - elif backing['state'].lower() == 'absent': - # remove serial port - serial_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.remove - self.change_applied = True - self.config_spec.deviceChange.append(serial_spec) - else: - self.module.fail_json(msg='Unable to find the specified serial port: %s' % backing) + elif backing['state'] == 'absent': + # remove serial port + serial_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.remove + self.change_applied = True + self.config_spec.deviceChange.append(serial_spec) + else: + if backing['state'] == 'present': + # if serial port is None + # create a new serial port + serial_port_spec = self.create_serial_port(backing) + serial_port_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add + self.serial_ports.append(serial_port_spec) + self.change_applied = True def reconfigure_vm_serial_port(self, vm_obj): """ @@ -330,7 +342,7 @@ def create_serial_port(self, backing): """ serial_spec = vim.vm.device.VirtualDeviceSpec() serial_port = vim.vm.device.VirtualSerialPort() - serial_port.yieldOnPoll = backing['yield_on_poll'] if 'yield_on_poll' in backing.keys() else True + serial_port.yieldOnPoll = backing['yield_on_poll'] serial_port.backing = self.get_backing_info(serial_port, backing, backing['type']) serial_spec.device = serial_port return serial_spec @@ -353,23 +365,19 @@ def get_serial_port(vm_obj, backing): if isinstance(device.backing, backing_type_mapping[backing['type']]): if 'service_uri' in valid_params: # network backing type - if device.backing.serviceURI == backing['service_uri']: - serial_port = device + serial_port = device break if 'pipe_name' in valid_params: # named pipe backing type - if device.backing.pipeName == backing['pipe_name']: - serial_port = device + serial_port = device break if 'device_name' in valid_params: # physical serial device backing type - if device.backing.deviceName == backing['device_name']: - serial_port = device + serial_port = device break if 'file_path' in valid_params: # file backing type - if device.backing.fileName == backing['file_path']: - serial_port = device + serial_port = device break # if there is a backing of only one type, user need not provide secondary details like service_uri, pipe_name, device_name or file_path # we will match the serial port with backing type only @@ -409,6 +417,29 @@ def get_serial_port_info(vm_obj): return serial_port_info +def diff_serial_port_config(serial_port, backing): + if 'yield_on_poll' in backing: + if serial_port.yieldOnPoll != backing['yield_on_poll']: + return True + if 'service_uri' in backing: + if serial_port.backing.serviceURI != backing['service_uri'] or \ + serial_port.backing.direction != backing['direction']: + return True + if 'pipe_name' in backing: + if serial_port.backing.pipeName != backing['pipe_name'] or \ + serial_port.backing.endpoint != backing['endpoint'] or \ + serial_port.backing.noRxLoss != backing['no_rx_loss']: + return True + if 'device_name' in backing: + if serial_port.backing.deviceName != backing['device_name']: + return True + if 'file_path' in backing: + if serial_port.backing.fileName != backing['file_path']: + return True + + return False + + def main(): """ Main method diff --git a/tests/integration/targets/vmware_guest_serial_port/tasks/main.yml b/tests/integration/targets/vmware_guest_serial_port/tasks/main.yml index 236176b3cb..8bbb3cb60f 100644 --- a/tests/integration/targets/vmware_guest_serial_port/tasks/main.yml +++ b/tests/integration/targets/vmware_guest_serial_port/tasks/main.yml @@ -33,7 +33,447 @@ that: - create_vm_for_test is changed -- name: Create multiple serial ports with Backing type - network, pipe, device and file +- name: "Create a new serial port for pipe type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + register: create_serial_port_pipe_type + +- assert: + that: + - create_serial_port_pipe_type.changed is sameas true + +- name: "Create a new serial port for pipe type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + register: create_serial_port_pipe_type_idempotency_check + +- assert: + that: + - create_serial_port_pipe_type_idempotency_check.changed is sameas false + +- name: "Update serial port for pipe type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: server + no_rx_loss: false + register: update_serial_port_pipe_type + +- assert: + that: + - update_serial_port_pipe_type.changed is sameas true + +- name: "Remove serial port for pipe type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: server + no_rx_loss: false + state: absent + register: remove_serial_port_pipe_type + +- assert: + that: + - remove_serial_port_pipe_type.changed is sameas true + +- name: "Remove serial port for pipe type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: server + no_rx_loss: false + state: absent + register: remove_serial_port_pipe_type_idempotency_check + +- assert: + that: + - remove_serial_port_pipe_type_idempotency_check.changed is sameas false + +- name: "Create a new serial port for network type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: network + service_uri: tcp://6000 + direction: client + register: create_serial_port_network_type + +- assert: + that: + - create_serial_port_network_type.changed is sameas true + +- name: "Create a new serial port for network type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: network + service_uri: tcp://6000 + direction: client + register: create_serial_port_network_type_idempotency_check + +- assert: + that: + - create_serial_port_network_type_idempotency_check.changed is sameas false + +- name: "Update serial port for network type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: network + service_uri: tcp://6000 + direction: server + register: update_serial_port_network_type + +- assert: + that: + - update_serial_port_network_type.changed is sameas true + +- name: "Remove serial port for network type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: network + service_uri: tcp://6000 + direction: server + state: absent + register: remove_serial_network_pipe_type + +- assert: + that: + - remove_serial_network_pipe_type.changed is sameas true + +- name: "Remove serial port for network type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: network + service_uri: tcp://6000 + direction: server + state: absent + register: remove_serial_port_network_type_idempotency_check + +- assert: + that: + - remove_serial_port_network_type_idempotency_check.changed is sameas false + +- name: "Create a new serial port for device type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: device + device_name: /dev/char/serial/uart0 + register: create_serial_port_device_type + +- assert: + that: + - create_serial_port_device_type.changed is sameas true + +- name: "Create a new serial port for device type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: device + device_name: /dev/char/serial/uart0 + register: create_serial_port_device_type_idempotency_check + +- assert: + that: + - create_serial_port_device_type_idempotency_check.changed is sameas false + +- name: "Update serial port for device type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: device + device_name: /dev/char/serial/uart1 + register: update_serial_port_device_type + +- assert: + that: + - update_serial_port_device_type.changed is sameas true + +- name: "Remove serial port for device type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: device + device_name: /dev/char/serial/uart1 + state: absent + register: remove_serial_network_device_type + +- assert: + that: + - remove_serial_network_device_type.changed is sameas true + +- name: "Remove serial port for device type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: device + device_name: /dev/char/serial/uart1 + state: absent + register: remove_serial_port_device_type_idempotency_check + +- assert: + that: + - remove_serial_port_device_type_idempotency_check.changed is sameas false + +- name: "Create a new serial port for file type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: file + file_path: "[{{ rw_datastore }}] file1" + register: create_serial_port_file_type + +- assert: + that: + - create_serial_port_file_type.changed is sameas true + +- name: "Create a new serial port for file type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: file + file_path: "[{{ rw_datastore }}] file1" + register: create_serial_port_file_type_idempotency_check + +- assert: + that: + - create_serial_port_file_type_idempotency_check.changed is sameas false + +- name: "Update serial port for file type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: file + file_path: "[{{ rw_datastore }}] file2" + register: update_serial_port_file_type + +- assert: + that: + - update_serial_port_file_type.changed is sameas true + +- name: "Remove serial port for file type" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: file + file_path: "[{{ rw_datastore }}] file2" + state: absent + register: remove_serial_network_file_type + +- assert: + that: + - remove_serial_network_file_type.changed is sameas true + +- name: "Remove serial port for file type(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: file + file_path: "[{{ rw_datastore }}] file2" + state: absent + register: remove_serial_port_file_type_idempotency_check + +- assert: + that: + - remove_serial_port_file_type_idempotency_check.changed is sameas false + +- name: "Create a new serial port for pipe type using yield_on_poll param" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + yield_on_poll: true + register: create_serial_port_pipe_type_using_yield_on_poll + +- assert: + that: + - create_serial_port_pipe_type_using_yield_on_poll.changed is sameas true + +- name: "Create a new serial port for pipe type using yield_on_poll param(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + yield_on_poll: true + register: create_serial_port_pipe_type_using_yield_on_poll_idempotency_check + +- assert: + that: + - create_serial_port_pipe_type_using_yield_on_poll_idempotency_check.changed is sameas false + +- name: "Update serial port for pipe type using yield_on_poll param" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + yield_on_poll: false + register: update_serial_port_pipe_type_using_yield_on_poll + +- assert: + that: + - update_serial_port_pipe_type_using_yield_on_poll.changed is sameas true + +- name: "Remove serial port for pipe type using yield_on_poll param" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + yield_on_poll: false + state: absent + register: remove_serial_port_pipe_type_using_yield_on_poll + +- assert: + that: + - remove_serial_port_pipe_type_using_yield_on_poll.changed is sameas true + +- name: "Remove serial port for pipe type using yield_on_poll param(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: pipe + pipe_name: test_pipe + endpoint: client + no_rx_loss: true + yield_on_poll: false + state: absent + register: remove_serial_port_pipe_type_using_yield_on_poll_idempotency_check + +- assert: + that: + - remove_serial_port_pipe_type_using_yield_on_poll_idempotency_check.changed is sameas false + +- name: "Create multiple serial ports with Backing type - network, pipe, device and file" vmware_guest_serial_port: hostname: "{{ vcenter_hostname }}" username: "{{ vcenter_username }}" @@ -48,21 +488,48 @@ - type: 'pipe' pipe_name: 'serial_pipe' endpoint: 'client' + no_rx_loss: true - type: 'device' device_name: '/dev/char/serial/uart0' - type: 'file' - file_path: '[{{ rw_datastore }}]/file1' + file_path: '[{{ rw_datastore }}] file1' yield_on_poll: True register: create_multiple_ports -- debug: var=create_multiple_ports +- name: assert that changes were made + assert: + that: + - create_multiple_ports.changed is sameas true +- name: "Create multiple serial ports with Backing type - network, pipe, device and file(idempotency check)" + vmware_guest_serial_port: + hostname: "{{ vcenter_hostname }}" + username: "{{ vcenter_username }}" + password: "{{ vcenter_password }}" + validate_certs: no + name: "test_vm1" + backings: + - type: 'network' + direction: 'client' + service_uri: 'tcp://6000' + yield_on_poll: True + - type: 'pipe' + pipe_name: 'serial_pipe' + endpoint: 'client' + no_rx_loss: true + - type: 'device' + device_name: '/dev/char/serial/uart0' + - type: 'file' + file_path: '[{{ rw_datastore }}] file1' + yield_on_poll: True + register: create_multiple_ports_idempotency_check + - name: assert that changes were made assert: that: - - create_multiple_ports is changed + - create_multiple_ports_idempotency_check.changed is sameas false -- name: Modify existing serial port with Backing type - network +- name: "Modify existing serial port with Backing type - network" vmware_guest_serial_port: hostname: "{{ vcenter_hostname }}" username: "{{ vcenter_username }}" @@ -76,14 +543,12 @@ service_uri: 'tcp://6000' register: modify_network_port -- debug: var=modify_network_port - - name: assert that changes were made assert: that: - - modify_network_port is changed + - modify_network_port.changed is sameas true -- name: Remove serial port with Backing type - pipe +- name: "Remove serial port with Backing type - pipe" vmware_guest_serial_port: hostname: "{{ vcenter_hostname }}" username: "{{ vcenter_username }}" @@ -95,9 +560,7 @@ state: 'absent' register: remove_pipe_port -- debug: var=remove_pipe_port - - name: assert that changes were made assert: that: - - remove_pipe_port is changed + - remove_pipe_port.changed is sameas true