Skip to content

Commit

Permalink
Fix vmware_guest_serial_port to have idempotency
Browse files Browse the repository at this point in the history
add changelog file

update integration test
  • Loading branch information
sky-joker committed Aug 23, 2020
1 parent 7e0f26f commit 254a235
Show file tree
Hide file tree
Showing 3 changed files with 540 additions and 44 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/358-vmware_guest_serial_port.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- vmware_guest_serial_port - fixed to have idepomtency.
95 changes: 63 additions & 32 deletions plugins/modules/vmware_guest_serial_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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).
Expand Down Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 254a235

Please sign in to comment.