
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
303 lines
9.3 KiB
Python
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()
|