1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-02-04 16:01:55 +00:00
community.general/plugins/modules/cobbler_system.py
patchback[bot] 4b9ece4fbd
[PR #11105/9b886739 backport][stable-12] replace batch of redundant to_native()/to_text() occurrences (#11139)
replace batch of redundant to_native()/to_text() occurrences (#11105)

* replace batch of redundant to_native()/to_text() occurrences

* add changelog frag

(cherry picked from commit 9b8867399e)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
2025-11-12 21:59:03 +01:00

339 lines
10 KiB
Python

#!/usr/bin/python
# Copyright (c) 2018, Dag Wieers (dagwieers) <dag@wieers.com>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
DOCUMENTATION = r"""
module: cobbler_system
short_description: Manage system objects in Cobbler
description:
- Add, modify or remove systems in Cobbler.
extends_documentation_fragment:
- community.general.attributes
attributes:
check_mode:
support: full
diff_mode:
support: full
options:
host:
description:
- The name or IP address of the Cobbler system.
default: 127.0.0.1
type: str
port:
description:
- Port number to be used for REST connection.
- The default value depends on parameter O(use_ssl).
type: int
username:
description:
- The username to log in to Cobbler.
default: cobbler
type: str
password:
description:
- The password to log in to Cobbler.
type: str
use_ssl:
description:
- If V(false), an HTTP connection is used instead of the default HTTPS connection.
type: bool
default: true
validate_certs:
description:
- If V(false), SSL certificates are not validated.
- This should only set to V(false) when used on personally controlled sites using self-signed certificates.
type: bool
default: true
name:
description:
- The system name to manage.
type: str
properties:
description:
- A dictionary with system properties.
type: dict
interfaces:
description:
- A list of dictionaries containing interface options.
type: dict
sync:
description:
- Sync on changes.
- Concurrently syncing Cobbler is bound to fail.
type: bool
default: false
state:
description:
- Whether the system should be present, absent or a query is made.
choices: [absent, present, query]
default: present
type: str
author:
- Dag Wieers (@dagwieers)
notes:
- Concurrently syncing Cobbler is bound to fail with weird errors.
"""
EXAMPLES = r"""
- name: Ensure the system exists in Cobbler
community.general.cobbler_system:
host: cobbler01
username: cobbler
password: MySuperSecureP4sswOrd
name: myhost
properties:
profile: CentOS6-x86_64
name_servers: [2.3.4.5, 3.4.5.6]
name_servers_search: foo.com, bar.com
interfaces:
eth0:
macaddress: 00:01:02:03:04:05
ipaddress: 1.2.3.4
delegate_to: localhost
- name: Enable network boot in Cobbler
community.general.cobbler_system:
host: bdsol-aci-cobbler-01
username: cobbler
password: ins3965!
name: bdsol-aci51-apic1.cisco.com
properties:
netboot_enabled: true
state: present
delegate_to: localhost
- name: Query all systems in Cobbler
community.general.cobbler_system:
host: cobbler01
username: cobbler
password: MySuperSecureP4sswOrd
state: query
register: cobbler_systems
delegate_to: localhost
- name: Query a specific system in Cobbler
community.general.cobbler_system:
host: cobbler01
username: cobbler
password: MySuperSecureP4sswOrd
name: '{{ inventory_hostname }}'
state: query
register: cobbler_properties
delegate_to: localhost
- name: Ensure the system does not exist in Cobbler
community.general.cobbler_system:
host: cobbler01
username: cobbler
password: MySuperSecureP4sswOrd
name: myhost
state: absent
delegate_to: localhost
"""
RETURN = r"""
systems:
description: List of systems.
returned: O(state=query) and O(name) is not provided
type: list
system:
description: (Resulting) information about the system we are working with.
returned: when O(name) is provided
type: dict
"""
import ssl
import xmlrpc.client as xmlrpc_client
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.general.plugins.module_utils.datetime import (
now,
)
IFPROPS_MAPPING = dict(
bondingopts="bonding_opts",
bridgeopts="bridge_opts",
connected_mode="connected_mode",
cnames="cnames",
dhcptag="dhcp_tag",
dnsname="dns_name",
ifgateway="if_gateway",
interfacetype="interface_type",
interfacemaster="interface_master",
ipaddress="ip_address",
ipv6address="ipv6_address",
ipv6defaultgateway="ipv6_default_gateway",
ipv6mtu="ipv6_mtu",
ipv6prefix="ipv6_prefix",
ipv6secondaries="ipv6_secondariesu",
ipv6staticroutes="ipv6_static_routes",
macaddress="mac_address",
management="management",
mtu="mtu",
netmask="netmask",
static="static",
staticroutes="static_routes",
virtbridge="virt_bridge",
)
def getsystem(conn, name, token):
system = dict()
if name:
# system = conn.get_system(name, token)
systems = conn.find_system(dict(name=name), token)
if systems:
system = systems[0]
return system
def main():
module = AnsibleModule(
argument_spec=dict(
host=dict(type="str", default="127.0.0.1"),
port=dict(type="int"),
username=dict(type="str", default="cobbler"),
password=dict(type="str", no_log=True),
use_ssl=dict(type="bool", default=True),
validate_certs=dict(type="bool", default=True),
name=dict(type="str"),
interfaces=dict(type="dict"),
properties=dict(type="dict"),
sync=dict(type="bool", default=False),
state=dict(type="str", default="present", choices=["absent", "present", "query"]),
),
supports_check_mode=True,
)
username = module.params["username"]
password = module.params["password"]
port = module.params["port"]
use_ssl = module.params["use_ssl"]
validate_certs = module.params["validate_certs"]
name = module.params["name"]
state = module.params["state"]
module.params["proto"] = "https" if use_ssl else "http"
if not port:
module.params["port"] = "443" if use_ssl else "80"
result = dict(
changed=False,
)
start = now()
ssl_context = None if validate_certs or not use_ssl else ssl._create_unverified_context()
url = "{proto}://{host}:{port}/cobbler_api".format(**module.params)
conn = xmlrpc_client.ServerProxy(url, context=ssl_context)
try:
token = conn.login(username, password)
except xmlrpc_client.Fault as e:
module.fail_json(
msg="Failed to log in to Cobbler '{url}' as '{username}'. {error}".format(
url=url, error=f"{e}", **module.params
)
)
except Exception as e:
module.fail_json(msg=f"Connection to '{url}' failed. {e}")
system = getsystem(conn, name, token)
# result['system'] = system
if state == "query":
if name:
result["system"] = system
else:
# Turn it into a dictionary of dictionaries
# all_systems = conn.get_systems()
# result['systems'] = { system['name']: system for system in all_systems }
# Return a list of dictionaries
result["systems"] = conn.get_systems()
elif state == "present":
if system:
# Update existing entry
system_id = ""
# https://github.com/cobbler/cobbler/blame/v3.3.7/cobbler/api.py#L277
if float(conn.version()) >= 3.4:
system_id = conn.get_system_handle(name)
else:
system_id = conn.get_system_handle(name, token)
for key, value in module.params["properties"].items():
if key not in system:
module.warn(f"Property '{key}' is not a valid system property.")
if system[key] != value:
try:
conn.modify_system(system_id, key, value, token)
result["changed"] = True
except Exception as e:
module.fail_json(msg=f"Unable to change '{key}' to '{value}'. {e}")
else:
# Create a new entry
system_id = conn.new_system(token)
conn.modify_system(system_id, "name", name, token)
result["changed"] = True
if module.params["properties"]:
for key, value in module.params["properties"].items():
try:
conn.modify_system(system_id, key, value, token)
except Exception as e:
module.fail_json(msg=f"Unable to change '{key}' to '{value}'. {e}")
# Add interface properties
interface_properties = dict()
if module.params["interfaces"]:
for device, values in module.params["interfaces"].items():
for key, value in values.items():
if key == "name":
continue
if key not in IFPROPS_MAPPING:
module.warn(f"Property '{key}' is not a valid system property.")
if not system or system["interfaces"][device][IFPROPS_MAPPING[key]] != value:
result["changed"] = True
interface_properties[f"{key}-{device}"] = value
if result["changed"] is True:
conn.modify_system(system_id, "modify_interface", interface_properties, token)
# Only save when the entry was changed
if not module.check_mode and result["changed"]:
conn.save_system(system_id, token)
elif state == "absent":
if system:
if not module.check_mode:
conn.remove_system(name, token)
result["changed"] = True
if not module.check_mode and module.params["sync"] and result["changed"]:
try:
conn.sync(token)
except Exception as e:
module.fail_json(msg=f"Failed to sync Cobbler. {e}")
if state in ("absent", "present"):
result["system"] = getsystem(conn, name, token)
if module._diff:
result["diff"] = dict(before=system, after=result["system"])
elapsed = now() - start
module.exit_json(elapsed=elapsed.seconds, **result)
if __name__ == "__main__":
main()