diff --git a/mreg_cli/commands/host_submodules/core.py b/mreg_cli/commands/host_submodules/core.py index 23d33663..fc0f1950 100644 --- a/mreg_cli/commands/host_submodules/core.py +++ b/mreg_cli/commands/host_submodules/core.py @@ -30,6 +30,7 @@ host_info_by_name, host_info_by_name_or_ip, ) +from mreg_cli.utilities.network import get_network_by_ip, ips_are_in_same_vlan from mreg_cli.utilities.output import output_host_info, output_ip_info from mreg_cli.utilities.shared import convert_wildcard_to_regex, format_mac from mreg_cli.utilities.validators import is_valid_email, is_valid_ip, is_valid_mac @@ -142,8 +143,12 @@ def add(args: argparse.Namespace) -> None: Flag("-force", action="store_true", description="Enable force."), Flag( "-override", - short_desc="Override list", - description="Override list for forcing (cname, naptr, srv, ptr)", + short_desc="Comma separated override list", + description=( + "Comma separated overrides for forced removal. " + "Supports the following overrides: 'cname', 'naptr', 'mxs', 'srv', 'ptr'. " + "Example usage: '-override cnames,ipaddresses,mxs'" + ), metavar="OVERRIDE", ), ], @@ -151,43 +156,61 @@ def add(args: argparse.Namespace) -> None: def remove(args: argparse.Namespace) -> None: """Remove host. - :param args: argparse.Namespace (name, force) + :param args: argparse.Namespace (name, force, override) """ # Get host info or raise exception info = host_info_by_name_or_ip(args.name) overrides: List[str] = args.override.split(",") if args.override else [] def forced(override_required: str = None) -> bool: - # If force wasn't set at all, return false. - if not args.force: - return False - + # If we require an override, check if it's in the list of provided overrides. if override_required: return override_required in overrides + # We didn't require an override, so we only need to check for force. + if args.force: + return True + + # And the fallback is "no". return False - warn_msg = "" + warnings: List[str] = [] # Require force if host has any cnames. - cnames = info["cnames"] - if len(cnames): - if not forced("cnames"): - warn_msg += "{} cnames. ".format(len(cnames)) - - # Require force if host has multiple A/AAAA records - if len(info["ipaddresses"]) > 1 and not forced(): - warn_msg += "{} ipaddresses. ".format(len(info["ipaddresses"])) + if info["cnames"] and not args.force: + warnings.append(f" {len(info['cnames'])} cnames, override with 'cnames'") + for cname in info["cnames"]: + warnings.append(f" - {cname['name']}") + + # Require force if host has multiple A/AAAA records and they are not in the same VLAN. + if len(info["ipaddresses"]) > 1: + same_vlan = ips_are_in_same_vlan([ip["ipaddress"] for ip in info["ipaddresses"]]) + + if same_vlan and not forced(): + warnings.append(" multiple ipaddresses on the same VLAN. Must use 'force'.") + elif not same_vlan and not forced("ipaddresses"): + warnings.append( + " {} ipaddresses on distinct VLANs, override with 'ipadresses'".format( + len(info["ipaddresses"]) + ) + ) + for ip in info["ipaddresses"]: + vlan = get_network_by_ip(ip["ipaddress"]).get("vlan") + warnings.append(f" - {ip['ipaddress']} (vlan: {vlan})") - if len(info["mxs"]) > 0 and not args.force: - warn_msg += "MX record(s). " + if info["mxs"] and not forced("mxs"): + warnings.append(f" {len(info['mxs'])} MX records, override with 'mxs'") + for mx in info["mxs"]: + warnings.append(f" - {mx['mx']} (priority: {mx['priority']})") # Require force if host has any NAPTR records. Delete the NAPTR records if # force path = "/api/v1/naptrs/" naptrs = get_list(path, params={"host": info["id"]}) if len(naptrs) > 0: - if not args.force: - warn_msg += "{} NAPTR records. ".format(len(naptrs)) + if not forced("naptrs"): + warnings.append(" {} NAPTR records. ".format(len(naptrs))) + for naptr in naptrs: + warnings.append(f" - {naptr['replacement']}") else: for naptr in naptrs: cli_info( @@ -201,8 +224,10 @@ def forced(override_required: str = None) -> bool: path = "/api/v1/srvs/" srvs = get_list(path, params={"host__name": info["name"]}) if len(srvs) > 0: - if not args.force: - warn_msg += "{} SRV records. ".format(len(srvs)) + if not forced("srvs"): + warnings.append(f" {len(srvs)} SRV records, override with 'srvs'") + for srv in srvs: + warnings.append(f" - {srv['name']}") else: for srv in srvs: cli_info( @@ -214,8 +239,10 @@ def forced(override_required: str = None) -> bool: # Require force if host has any PTR records. Delete the PTR records if force if len(info["ptr_overrides"]) > 0: - if not args.force: - warn_msg += "{} PTR records. ".format(len(info["ptr_overrides"])) + if not forced("ptr"): + warnings.append(f" {len(info['ptr_overrides'])} PTR records, override with 'ptr'") + for ptr in info["ptr_overrides"]: + warnings.append(f" - {ptr['ipaddress']}") else: for ptr in info["ptr_overrides"]: cli_info( @@ -231,8 +258,9 @@ def forced(override_required: str = None) -> bool: info["ipaddress"] = info["ipaddresses"][0]["ipaddress"] # Warn user and raise exception if any force requirements was found - if warn_msg: - cli_warning("{} has: {}Must force".format(info["name"], warn_msg)) + if warnings: + warn_msg = "\n".join(warnings) + cli_warning("{} will require override for deletion:\n{}".format(info["name"], warn_msg)) # Delete host path = f"/api/v1/hosts/{info['name']}" diff --git a/mreg_cli/utilities/network.py b/mreg_cli/utilities/network.py index 0c0447da..8ae47b9d 100644 --- a/mreg_cli/utilities/network.py +++ b/mreg_cli/utilities/network.py @@ -56,7 +56,7 @@ def ips_are_in_same_vlan(ips: List[str]) -> bool: last_vlan = network["vlan"] - return False + return True def get_network_by_ip(ip: str) -> Dict[str, Any]: