|
|
|
@ -12,6 +12,8 @@ from typing import Union
|
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
|
|
|
|
import argcomplete
|
|
|
|
|
import openstack
|
|
|
|
|
import openstack.config.loader
|
|
|
|
|
import requests
|
|
|
|
|
import yaml
|
|
|
|
|
from requests.models import HTTPBasicAuth
|
|
|
|
@ -43,6 +45,21 @@ def get_config(config_filename: str):
|
|
|
|
|
return yaml.safe_load(fh.read())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_openstack_addresses(name: str, cloud: str):
|
|
|
|
|
conn = openstack.connect(cloud=cloud)
|
|
|
|
|
|
|
|
|
|
# List the servers
|
|
|
|
|
server = conn.compute.find_server(name)
|
|
|
|
|
if server is None:
|
|
|
|
|
print("Server not found")
|
|
|
|
|
exit(1)
|
|
|
|
|
openstack_addresses = []
|
|
|
|
|
for network in server.addresses:
|
|
|
|
|
for address in network:
|
|
|
|
|
openstack_addresses.append(address)
|
|
|
|
|
return openstack_addresses
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def nested_out(input, tabs="") -> str:
|
|
|
|
|
string = ""
|
|
|
|
|
if isinstance(input, str) or isinstance(input, int):
|
|
|
|
@ -208,6 +225,84 @@ def run_list(url: str,
|
|
|
|
|
output(string, jsonout)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_openstack_sync(cloud: str, name: str, zone: str, headers: dict,
|
|
|
|
|
baseurl: str, jsonout: bool):
|
|
|
|
|
url = setup_url(
|
|
|
|
|
baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
)
|
|
|
|
|
current_records = run_list(url, jsonout=True, headers=headers, ret=True)
|
|
|
|
|
openstack_addresses = get_openstack_addresses(cloud, name)
|
|
|
|
|
if current_records is None:
|
|
|
|
|
for address in openstack_addresses:
|
|
|
|
|
rtype = None
|
|
|
|
|
if address.version == 4:
|
|
|
|
|
rtype = "A"
|
|
|
|
|
elif address.version == 6:
|
|
|
|
|
rtype = "AAAA"
|
|
|
|
|
if rtype:
|
|
|
|
|
url = setup_url(baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
rtype=rtype,
|
|
|
|
|
data=address.addr)
|
|
|
|
|
run_add(url, jsonout, headers)
|
|
|
|
|
else:
|
|
|
|
|
previpv4, previpv6, curripv4, curripv6 = False
|
|
|
|
|
for record in current_records:
|
|
|
|
|
if record["type"] == "A":
|
|
|
|
|
previpv4 = record["data"]
|
|
|
|
|
elif record["type"] == "AAAA":
|
|
|
|
|
previpv6 = record["data"]
|
|
|
|
|
for address in openstack_addresses:
|
|
|
|
|
rtype = None
|
|
|
|
|
if address.version == 4:
|
|
|
|
|
rtype = "A"
|
|
|
|
|
curripv4 = True
|
|
|
|
|
elif address.version == 6:
|
|
|
|
|
rtype = "AAAA"
|
|
|
|
|
curripv6 = True
|
|
|
|
|
if rtype and record["type"] == rtype:
|
|
|
|
|
if record["data"] == address.addr:
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
url = setup_url(baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
rtype=record["type"],
|
|
|
|
|
data=address.addr)
|
|
|
|
|
run_update(url, jsonout, headers)
|
|
|
|
|
if previpv4 and not curripv4:
|
|
|
|
|
url = setup_url(baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
rtype="A",
|
|
|
|
|
data=previpv4)
|
|
|
|
|
run_delete(url, jsonout, headers)
|
|
|
|
|
if previpv6 and not curripv6:
|
|
|
|
|
url = setup_url(baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
rtype="AAAA",
|
|
|
|
|
data=previpv4)
|
|
|
|
|
run_delete(url, jsonout, headers)
|
|
|
|
|
if curripv4 and not previpv4:
|
|
|
|
|
url = setup_url(baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
rtype="A",
|
|
|
|
|
data=curripv4)
|
|
|
|
|
run_add(url, jsonout, headers)
|
|
|
|
|
if curripv6 and not previpv6:
|
|
|
|
|
url = setup_url(baseurl,
|
|
|
|
|
zone=zone,
|
|
|
|
|
name=name,
|
|
|
|
|
rtype="AAAA",
|
|
|
|
|
data=curripv6)
|
|
|
|
|
run_add(url, jsonout, headers)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_update(url: str, jsonout: bool, headers: dict):
|
|
|
|
|
response = requests.patch(url, headers=headers)
|
|
|
|
|
output(response.json(), jsonout)
|
|
|
|
@ -415,6 +510,13 @@ def get_parser() -> dict:
|
|
|
|
|
listcmd.add_argument("-r", "--rtype")
|
|
|
|
|
listcmd.add_argument("-z", "--zone", required=False)
|
|
|
|
|
|
|
|
|
|
openstack_description = "Sync records with openstack."
|
|
|
|
|
openstackcmd = subparsers.add_parser("openstack-sync",
|
|
|
|
|
description=openstack_description)
|
|
|
|
|
openstackcmd.add_argument("-n", "--name", required=True)
|
|
|
|
|
openstackcmd.add_argument("-c", "--cloud", required=True)
|
|
|
|
|
openstackcmd.add_argument("-z", "--zone", required=True)
|
|
|
|
|
|
|
|
|
|
user_description = "View user information."
|
|
|
|
|
usercmd = subparsers.add_parser("user", description=user_description)
|
|
|
|
|
usercmd.add_argument("-u", "--username", default=None)
|
|
|
|
@ -500,6 +602,9 @@ def run(url, args, headers, baseurl, parser, username):
|
|
|
|
|
elif args.command == "zone":
|
|
|
|
|
url = baseurl + "/zones"
|
|
|
|
|
run_zone(url, args.json, headers)
|
|
|
|
|
elif args.command == "openstack-sync":
|
|
|
|
|
run_openstack_sync(args.cloud, args.name, args.zone, headers,
|
|
|
|
|
baseurl, args.json)
|
|
|
|
|
else:
|
|
|
|
|
parser.print_help(sys.stderr)
|
|
|
|
|
return 2
|
|
|
|
@ -564,7 +669,9 @@ def main() -> int:
|
|
|
|
|
if args.command == "user":
|
|
|
|
|
if args.username:
|
|
|
|
|
user = args.username
|
|
|
|
|
if args.command in ["auditlog", "changelog", "user", "zone"]:
|
|
|
|
|
if args.command in [
|
|
|
|
|
"auditlog", "changelog", "openstack-sync", "user", "zone"
|
|
|
|
|
]:
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|