Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enables pure IPv6 configurations for nd_setup module on ND version 3.0.1 and later (DCNE-241) #108

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/module_utils/nd_argument_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def ntp_keys_spec():

def network_spec(vlan=False):
spec = dict(
ipv4_address=dict(type="str", aliases=["ip"], required=True),
ipv4_gateway=dict(type="str", aliases=["gateway"], required=True),
ipv4_address=dict(type="str", aliases=["ip"]),
ipv4_gateway=dict(type="str", aliases=["gateway"]),
ipv6_address=dict(type="str"),
ipv6_gateway=dict(type="str"),
)
Expand Down
71 changes: 47 additions & 24 deletions plugins/modules/nd_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@
description:
- The management IP address of the node.
type: str
required: true
username:
description:
- The username of the node.
Expand All @@ -185,13 +184,11 @@
description:
- The IPv4 address of the management network.
type: str
required: true
aliases: [ ip ]
ipv4_gateway:
description:
- The IPv4 gateway of the management network.
type: str
required: true
aliases: [ gateway ]
ipv6_address:
description:
Expand All @@ -211,13 +208,11 @@
description:
- The IPv4 address of the data network.
type: str
required: true
aliases: [ ip ]
ipv4_gateway:
description:
- The IPv4 gateway of the data network.
type: str
required: true
aliases: [ gateway ]
ipv6_address:
description:
Expand Down Expand Up @@ -270,7 +265,7 @@
- This option is only applicable for ND version 3.1.1 and later.
type: list
elements: str
choices: [ ndo, ndfc, ndi ]
choices: [ ndo, ndfc, ndi-virtual, ndi-physical ]
aliases: [ mode ]
external_services:
description:
Expand Down Expand Up @@ -357,11 +352,21 @@
from ansible_collections.cisco.nd.plugins.module_utils.constants import ND_SETUP_NODE_ROLE_MAPPING


def check_network_requirements(nd, version, type, network):
if version >= "3.0.1":
if not all(network.get(ip) for ip in ["ipv6Subnet", "gatewayv6"]) and not all(network.get(ip) for ip in ["ipSubnet", "gateway"]):
nd.fail_json(msg="Missing IPv4 subnet/gateway or IPv6 subnet/gateway in node {0} configuration.".format(type))
else:
if not all(network.get(ip) for ip in ["ipSubnet", "gateway"]):
nd.fail_json(msg="Missing IPv4 subnet/gateway in node {0} configuration.".format(type))
return network


def main():
argument_spec = nd_argument_spec()
argument_spec.update(
cluster_name=dict(type="str"),
deployment_mode=dict(type="list", elements="str", choices=["ndo", "ndfc", "ndi"], aliases=["mode"]),
deployment_mode=dict(type="list", elements="str", choices=["ndo", "ndfc", "ndi-virtual", "ndi-physical"], aliases=["mode"]),
external_services=dict(
type="dict",
options=dict(
Expand Down Expand Up @@ -394,7 +399,7 @@ def main():
hostname=dict(type="str", required=True),
serial_number=dict(type="str", required=True),
role=dict(type="str", default="primary", choices=["primary", "secondary", "standby"], aliases=["type"]),
management_ip_address=dict(type="str", required=True),
management_ip_address=dict(type="str"),
username=dict(type="str", required=True),
password=dict(type="str", required=True, no_log=True),
management_network=dict(type="dict", required=True, options=network_spec()),
Expand All @@ -409,7 +414,7 @@ def main():
argument_spec=argument_spec,
supports_check_mode=True,
required_if=[
["state", "present", ["cluster_name", "dns_server", "app_network", "service_network", "nodes"]],
["state", "present", ["cluster_name", "dns_server", "nodes"]],
],
required_together=[
["proxy_username", "proxy_password"],
Expand Down Expand Up @@ -442,6 +447,14 @@ def main():
if state == "query":
nd.existing = nd.request("/clusterstatus/install", method="GET")
else:
nd_version = nd.query_obj("/version.json")
nd_version = ".".join(str(nd_version[key]) for key in ["major", "minor", "maintenance"])
if nd_version >= "3.0.1":
if not all((app_network, service_network)) and not all((app_network_ipv6, service_network_ipv6)):
nd.fail_json(msg="Application and service network addresses, IPv4 or IPv6, are required during ND setup.")
else:
if not all((app_network, service_network)):
nd.fail_json(msg="Application and service network IPv4 addresses are required during ND setup.")
gmicol marked this conversation as resolved.
Show resolved Hide resolved
if len(cluster_name) > 63:
nd.fail_json("A length of 1 to 63 characters is allowed.")
elif len(re.findall(r"[^a-zA-Z0-9-]", cluster_name)) > 0:
Expand Down Expand Up @@ -492,19 +505,29 @@ def main():
"hostName": node.get("hostname"),
"serialNumber": node.get("serial_number"),
"role": ND_SETUP_NODE_ROLE_MAPPING.get(node.get("role")),
"dataNetwork": {
"ipSubnet": node["data_network"].get("ipv4_address"),
"gateway": node["data_network"].get("ipv4_gateway"),
"ipv6Subnet": node["data_network"].get("ipv6_address"),
"gatewayv6": node["data_network"].get("ipv6_gateway"),
"vlan": node["data_network"].get("vlan"),
},
"managementNetwork": {
"ipSubnet": node["management_network"].get("ipv4_address"),
"gateway": node["management_network"].get("ipv4_gateway"),
"ipv6Subnet": node["management_network"].get("ipv6_address"),
"gatewayv6": node["management_network"].get("ipv6_gateway"),
},
"dataNetwork": check_network_requirements(
nd,
nd_version,
"data network",
{
"ipSubnet": node["data_network"].get("ipv4_address"),
"gateway": node["data_network"].get("ipv4_gateway"),
"ipv6Subnet": node["data_network"].get("ipv6_address"),
"gatewayv6": node["data_network"].get("ipv6_gateway"),
"vlan": node["data_network"].get("vlan"),
},
),
"managementNetwork": check_network_requirements(
nd,
nd_version,
"management network",
{
"ipSubnet": node["management_network"].get("ipv4_address"),
"gateway": node["management_network"].get("ipv4_gateway"),
"ipv6Subnet": node["management_network"].get("ipv6_address"),
"gatewayv6": node["management_network"].get("ipv6_gateway"),
},
),
"bgpConfig": {
"as": node.get("bgp").get("asn") if node.get("bgp") is not None else None,
"peers": node.get("bgp").get("peers") if node.get("bgp") is not None else None,
Expand All @@ -520,9 +543,9 @@ def main():
}

# Deployment mode options introduced in ND version 3.1.1
if isinstance(deployment_mode, list):
if isinstance(deployment_mode, list) and nd_version >= "3.1.1":
payload["clusterConfig"]["deploymentMode"] = deployment_mode if len(deployment_mode) > 1 else deployment_mode[0]
if external_services is not None and any(service in {"ndi", "ndfc"} for service in deployment_mode):
if external_services is not None and any(service in {"ndi-virtual", "ndi-physical", "ndfc"} for service in deployment_mode):
payload["clusterConfig"]["externalServices"] = []
if external_services.get("management_service_ips") is not None:
payload["clusterConfig"]["externalServices"].append(
Expand Down
19 changes: 19 additions & 0 deletions tests/integration/targets/nd_setup/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,24 @@
cluster_name: clusterone-
ignore_errors: true
register: cluster_name_invalid_hyphen

- name: Install ND without management network ipv4 address
cisco.nd.nd_setup:
<<: *nd_setup_test_config
nodes:
- hostname: Test
serial_number: "{{ serial_number }}"
role: primary
management_ip_address: "{{ management_ip_address }}"
username: "{{ deployment_username | default('rescue-user') }}"
password: "{{ deployment_password }}"
management_network:
ipv4_gateway: "{{ management_gateway }}"
gmicol marked this conversation as resolved.
Show resolved Hide resolved
data_network:
ipv4_address: "{{ data_ip }}"
ipv4_gateway: "{{ data_gateway }}"
ignore_errors: true
register: cluster_invalid_node_management_network

- name: Install ND in normal mode
cisco.nd.nd_setup:
Expand All @@ -290,6 +308,7 @@
- cluster_name_length_error.msg == "A length of 1 to 63 characters is allowed."
- cluster_name_invalid_chars.msg == "Valid characters include letters, digits and hyphen."
- cluster_name_invalid_hyphen.msg == "The name cannot start or end with a hyphen."
- cluster_invalid_node_management_network.msg == "Missing IPv4 subnet/gateway or IPv6 subnet/gateway in node management network configuration."
- cluster_cm.current.clusterConfig.appNetwork == "{{ app_network }}"
- cluster_cm.current.clusterConfig.nameServers.0 == "{{ dns_server }}"
- cluster_cm.current.clusterConfig.ntpConfig.servers.0.host == "{{ ntp_server }}"
Expand Down
Loading