Jakob Meng 99074ccd12 Refactored baremetal_port and baremetal_port_info modules
Sorted argument specs and documentation of both modules.

Refactored both modules to be subclasses of OpenStackModule class.

Renamed baremetal_port's module attributes 'uuid' to 'id' and
'portgroup' to 'port_group' to match openstacksdk. Added the previous
attribute names as aliases to keep backward compatibility. Added
alias 'pxe_enabled' for 'is_pxe_enabled' which was previously set
programmatically.

Changed baremetal_port module to return attribute 'port' only when
state is present. It will return no values (except Ansible's default
values) when state is absent. Previous return value 'id' can be
retrieved from port's dictionary entry 'id'.
The non-standard return value 'result' has been dropped because its
content can easily be reconstructed with Ansible's is changed check.

The non-standard return value 'changes' has been dropped because its
content was only returned on updates, has no known uses and can
easily be reconstructed in Ansible by comparing the updated port
dictionary with a copy of the pre-updated port dictionary.

Module baremetal_port_info will no longer fail when no port with a
matching id or name or address could be found. Instead it will return
an empty list like other *_info modules.

baremetal_port_info's return attribute 'baremetal_ports' has been
renamed to 'ports' to be consistent with other modules. The former
name will keep to be available for now to keep backward compatibility.

Both modules convert their return values into dictionaries without
computed (redundant) values. They do not drop values such as links
anymore though, because we do not withhold information from users.

Updated DOCUMENTATION, EXAMPLES and RETURN docstrings in both modules.

Added integration tests for both modules. They will not run in CI atm,
because we do not have Ironic enabled in our DevStack environment.

Change-Id: I54b3ea9917fbbbdf381ef934a0d92e2857f6d51b
2022-10-25 11:31:07 +02:00

303 lines
9.3 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2021 by Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
DOCUMENTATION = r'''
module: baremetal_port
short_description: Create/Delete Bare Metal port Resources from OpenStack
author: OpenStack Ansible SIG
description:
- Create, Update and Remove ironic ports from OpenStack.
options:
address:
description:
- Physical hardware address of this network Port, typically the
hardware MAC address.
type: str
extra:
description:
- A set of one or more arbitrary metadata key and value pairs.
type: dict
id:
description:
- ID of the Port.
- Will be auto-generated if not specified.
type: str
aliases: ['uuid']
is_pxe_enabled:
description:
- Whether PXE should be enabled or disabled on the Port.
type: bool
aliases: ['pxe_enabled']
local_link_connection:
description:
- The Port binding profile.
type: dict
suboptions:
switch_id:
description:
- A MAC address or an OpenFlow based datapath_id of the switch.
type: str
port_id:
description:
- Identifier of the physical port on the switch to which node's
port is connected to.
type: str
switch_info:
description:
- An optional string field to be used to store any vendor-specific
information.
type: str
node:
description:
- ID or Name of the Node this resource belongs to.
type: str
physical_network:
description:
- The name of the physical network to which a port is connected.
type: str
port_group:
description:
- ID or Name of the portgroup this resource belongs to.
type: str
aliases: ['portgroup']
state:
description:
- Indicates desired state of the resource
choices: ['present', 'absent']
default: present
type: str
requirements:
- "python >= 3.6"
- "openstacksdk"
extends_documentation_fragment:
- openstack.cloud.openstack
'''
EXAMPLES = r'''
- name: Create Bare Metal port
openstack.cloud.baremetal_port:
cloud: devstack
state: present
node: bm-0
address: fa:16:3e:aa:aa:aa
is_pxe_enabled: True
local_link_connection:
switch_id: 0a:1b:2c:3d:4e:5f
port_id: Ethernet3/1
switch_info: switch1
extra:
something: extra
physical_network: datacenter
register: result
- name: Delete Bare Metal port
openstack.cloud.baremetal_port:
cloud: devstack
state: absent
address: fa:16:3e:aa:aa:aa
register: result
- name: Update Bare Metal port
openstack.cloud.baremetal_port:
cloud: devstack
state: present
id: 1a85ebca-22bf-42eb-ad9e-f640789b8098
is_pxe_enabled: False
local_link_connection:
switch_id: a0:b1:c2:d3:e4:f5
port_id: Ethernet4/12
switch_info: switch2
'''
RETURN = r'''
port:
description: A port dictionary, subset of the dictionary keys listed below
may be returned, depending on your cloud provider.
returned: success
type: dict
contains:
address:
description: Physical hardware address of this network Port,
typically the hardware MAC address.
returned: success
type: str
created_at:
description: Bare Metal port created at timestamp.
returned: success
type: str
extra:
description: A set of one or more arbitrary metadata key and value
pairs.
returned: success
type: dict
id:
description: The UUID for the Baremetal Port resource.
returned: success
type: str
internal_info:
description: Internal metadata set and stored by the Port. This
field is read-only.
returned: success
type: dict
is_pxe_enabled:
description: Whether PXE is enabled or disabled on the Port.
returned: success
type: bool
links:
description: A list of relative links, including the self and
bookmark links.
returned: success
type: list
local_link_connection:
description: The Port binding profile. If specified, must contain
switch_id (only a MAC address or an OpenFlow based
datapath_id of the switch are accepted in this field
and port_id (identifier of the physical port on the
switch to which node's port is connected to) fields.
switch_info is an optional string field to be used to
store any vendor-specific information.
returned: success
type: dict
location:
description: Cloud location of this resource (cloud, project,
region, zone)
returned: success
type: dict
name:
description: Bare Metal port name.
returned: success
type: str
node_id:
description: UUID of the Bare Metal Node this resource belongs to.
returned: success
type: str
physical_network:
description: The name of the physical network to which a port is
connected.
returned: success
type: str
port_group_id:
description: UUID of the Portgroup this resource belongs to.
returned: success
type: str
updated_at:
description: Bare Metal port updated at timestamp.
returned: success
type: str
'''
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (
OpenStackModule
)
class BaremetalPortModule(OpenStackModule):
argument_spec = dict(
address=dict(),
extra=dict(type='dict'),
id=dict(aliases=['uuid']),
is_pxe_enabled=dict(type='bool', aliases=['pxe_enabled']),
local_link_connection=dict(type='dict'),
node=dict(),
physical_network=dict(),
port_group=dict(aliases=['portgroup']),
state=dict(default='present', choices=['present', 'absent']),
)
module_kwargs = dict(
required_one_of=[
('id', 'address'),
],
required_if=[
('state', 'present', ('node', 'address',), False),
],
)
def run(self):
port = self._find_port()
state = self.params['state']
if state == 'present':
# create or update port
kwargs = {}
id = self.params['id']
if id:
kwargs['id'] = id
node_name_or_id = self.params['node']
# assert node_name_or_id
node = self.conn.baremetal.find_node(node_name_or_id,
ignore_missing=False)
kwargs['node_id'] = node['id']
port_group_name_or_id = self.params['port_group']
if port_group_name_or_id:
port_group = self.conn.baremetal.find_port_group(
port_group_name_or_id, ignore_missing=False)
kwargs['port_group_id'] = port_group['id']
for k in ['address', 'extra', 'is_pxe_enabled',
'local_link_connection', 'physical_network']:
if self.params[k] is not None:
kwargs[k] = self.params[k]
changed = True
if not port:
# create port
port = self.conn.baremetal.create_port(**kwargs)
else:
# update port
updates = dict((k, v)
for k, v in kwargs.items()
if v != port[k])
if updates:
port = \
self.conn.baremetal.update_port(port['id'], **updates)
else:
changed = False
self.exit_json(changed=changed, port=port.to_dict(computed=False))
if state == 'absent':
# remove port
if not port:
self.exit_json(changed=False)
port = self.conn.baremetal.delete_port(port['id'])
self.exit_json(changed=True)
def _find_port(self):
id = self.params['id']
if id:
return self.conn.baremetal.get_port(id)
address = self.params['address']
if address:
ports = list(self.conn.baremetal.ports(address=address,
details=True))
if len(ports) == 1:
return ports[0]
elif len(ports) > 1:
raise ValueError(
'Multiple ports with address {address} found. A ID'
' must be defined in order to identify a unique'
' port.'.format(address=address))
else:
return None
raise AssertionError("id or address must be specified")
def main():
module = BaremetalPortModule()
module()
if __name__ == "__main__":
main()