|
|
@ -2,12 +2,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
import argparse
|
|
|
|
import getpass
|
|
|
|
import getpass
|
|
|
|
import json
|
|
|
|
|
|
|
|
import os
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import sys
|
|
|
|
import urllib.parse
|
|
|
|
import urllib.parse
|
|
|
|
from os import environ, mkdir
|
|
|
|
|
|
|
|
from os.path import isdir, isfile, join
|
|
|
|
|
|
|
|
from typing import Union
|
|
|
|
from typing import Union
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
|
|
|
|
|
@ -19,30 +16,29 @@ import yaml
|
|
|
|
from requests.models import HTTPBasicAuth
|
|
|
|
from requests.models import HTTPBasicAuth
|
|
|
|
from simplejson.errors import JSONDecodeError as SimplejsonJSONDecodeError
|
|
|
|
from simplejson.errors import JSONDecodeError as SimplejsonJSONDecodeError
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from .config import Config
|
|
|
|
|
|
|
|
from .utils import error, output
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
from requests.exceptions import JSONDecodeError as RequestsJSONDecodeError
|
|
|
|
from requests.exceptions import JSONDecodeError as RequestsJSONDecodeError
|
|
|
|
except ImportError:
|
|
|
|
except ImportError:
|
|
|
|
from requests.exceptions import InvalidJSONError as RequestsJSONDecodeError
|
|
|
|
from requests.exceptions import InvalidJSONError as RequestsJSONDecodeError
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Helper functions
|
|
|
|
class Knotctl:
|
|
|
|
def error(description: str, error: str) -> list[dict]:
|
|
|
|
|
|
|
|
response = []
|
|
|
|
|
|
|
|
reply = {}
|
|
|
|
|
|
|
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406
|
|
|
|
|
|
|
|
reply["Code"] = 406
|
|
|
|
|
|
|
|
reply["Description"] = description
|
|
|
|
|
|
|
|
reply["Error"] = error
|
|
|
|
|
|
|
|
response.append(reply)
|
|
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
|
|
|
self.conf = Config()
|
|
|
|
|
|
|
|
self.config = self.get_config()
|
|
|
|
|
|
|
|
self.config_filename = self.conf.config_filename
|
|
|
|
|
|
|
|
|
|
|
|
def get_config(config_filename: str):
|
|
|
|
def get_config(self):
|
|
|
|
if not isfile(config_filename):
|
|
|
|
config = self.conf.get_config()
|
|
|
|
|
|
|
|
if not config:
|
|
|
|
print("You need to configure knotctl before proceeding")
|
|
|
|
print("You need to configure knotctl before proceeding")
|
|
|
|
run_config(config_filename)
|
|
|
|
run_config()
|
|
|
|
with open(config_filename, "r") as fh:
|
|
|
|
|
|
|
|
return yaml.safe_load(fh.read())
|
|
|
|
return config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_openstack_addresses(cloud: str, name: str):
|
|
|
|
def get_openstack_addresses(cloud: str, name: str):
|
|
|
@ -60,30 +56,6 @@ def get_openstack_addresses(cloud: str, name: str):
|
|
|
|
return openstack_addresses
|
|
|
|
return openstack_addresses
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def nested_out(input, tabs="") -> str:
|
|
|
|
|
|
|
|
string = ""
|
|
|
|
|
|
|
|
if isinstance(input, str) or isinstance(input, int):
|
|
|
|
|
|
|
|
string += "{}\n".format(input)
|
|
|
|
|
|
|
|
elif isinstance(input, dict):
|
|
|
|
|
|
|
|
for key, value in input.items():
|
|
|
|
|
|
|
|
string += "{}{}: {}".format(tabs, key,
|
|
|
|
|
|
|
|
nested_out(value, tabs + " "))
|
|
|
|
|
|
|
|
elif isinstance(input, list):
|
|
|
|
|
|
|
|
for entry in input:
|
|
|
|
|
|
|
|
string += "{}\n{}".format(tabs, nested_out(entry, tabs + " "))
|
|
|
|
|
|
|
|
return string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def output(response: list[dict], jsonout: bool = False):
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
if jsonout:
|
|
|
|
|
|
|
|
print(json.dumps(response))
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
print(nested_out(response))
|
|
|
|
|
|
|
|
except BrokenPipeError:
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Define the runner for each command
|
|
|
|
# Define the runner for each command
|
|
|
|
def run_add(url: str, jsonout: bool, headers: dict):
|
|
|
|
def run_add(url: str, jsonout: bool, headers: dict):
|
|
|
|
parsed = split_url(url)
|
|
|
|
parsed = split_url(url)
|
|
|
@ -152,7 +124,6 @@ def run_complete(shell: Union[None, str]):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_config(
|
|
|
|
def run_config(
|
|
|
|
config_filename: str,
|
|
|
|
|
|
|
|
context: Union[None, str] = None,
|
|
|
|
context: Union[None, str] = None,
|
|
|
|
baseurl: Union[None, str] = None,
|
|
|
|
baseurl: Union[None, str] = None,
|
|
|
|
list_config: bool = False,
|
|
|
|
list_config: bool = False,
|
|
|
@ -160,29 +131,18 @@ def run_config(
|
|
|
|
password: Union[None, str] = None,
|
|
|
|
password: Union[None, str] = None,
|
|
|
|
current: Union[None, str] = None,
|
|
|
|
current: Union[None, str] = None,
|
|
|
|
):
|
|
|
|
):
|
|
|
|
|
|
|
|
conf = Config()
|
|
|
|
if current:
|
|
|
|
if current:
|
|
|
|
if os.path.islink(config_filename):
|
|
|
|
print(conf.get_current())
|
|
|
|
actual_path = os.readlink(config_filename)
|
|
|
|
|
|
|
|
print(actual_path.split("-")[-1])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
print("none")
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
config = {"baseurl": baseurl, "username": username, "password": password}
|
|
|
|
config = {"baseurl": baseurl, "username": username, "password": password}
|
|
|
|
needed = []
|
|
|
|
needed = []
|
|
|
|
if context:
|
|
|
|
if context:
|
|
|
|
symlink = f"{config_filename}-{context}"
|
|
|
|
found = conf.set_context(context)
|
|
|
|
found = os.path.isfile(symlink)
|
|
|
|
|
|
|
|
if os.path.islink(config_filename):
|
|
|
|
|
|
|
|
os.remove(config_filename)
|
|
|
|
|
|
|
|
elif os.path.isfile(config_filename):
|
|
|
|
|
|
|
|
os.rename(config_filename, symlink)
|
|
|
|
|
|
|
|
os.symlink(symlink, config_filename)
|
|
|
|
|
|
|
|
config_filename = symlink
|
|
|
|
|
|
|
|
if found:
|
|
|
|
if found:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
if list_config:
|
|
|
|
if list_config:
|
|
|
|
config_data = get_config(config_filename)
|
|
|
|
config_data = conf.get_config_data()
|
|
|
|
config_data.pop("password", None)
|
|
|
|
|
|
|
|
output(config_data)
|
|
|
|
output(config_data)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
if not baseurl:
|
|
|
|
if not baseurl:
|
|
|
@ -206,8 +166,7 @@ def run_config(
|
|
|
|
output(error("Can not configure without password", "No password"))
|
|
|
|
output(error("Can not configure without password", "No password"))
|
|
|
|
sys.exit(1)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
with open(config_filename, "w") as fh:
|
|
|
|
conf.set_config(config)
|
|
|
|
fh.write(yaml.dump(config))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run_delete(url: str, jsonout: bool, headers: dict):
|
|
|
|
def run_delete(url: str, jsonout: bool, headers: dict):
|
|
|
@ -280,7 +239,7 @@ def run_openstack_sync(cloud: str, name: str, zone: str, headers: dict,
|
|
|
|
elif address.version == 6:
|
|
|
|
elif address.version == 6:
|
|
|
|
rtype = "AAAA"
|
|
|
|
rtype = "AAAA"
|
|
|
|
curripv6 = True
|
|
|
|
curripv6 = True
|
|
|
|
if rtype and recor.type == rtype:
|
|
|
|
if rtype and record.type == rtype:
|
|
|
|
if record.data == address.addr:
|
|
|
|
if record.data == address.addr:
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
else:
|
|
|
@ -665,16 +624,10 @@ def main() -> int:
|
|
|
|
run_complete(args.shell)
|
|
|
|
run_complete(args.shell)
|
|
|
|
return 0
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
# Make sure we have config
|
|
|
|
knotctl = Knotctl()
|
|
|
|
config_basepath = join(environ["HOME"], ".knot")
|
|
|
|
|
|
|
|
config_filename = join(config_basepath, "config")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not isdir(config_basepath):
|
|
|
|
|
|
|
|
mkdir(config_basepath)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if args.command == "config":
|
|
|
|
if args.command == "config":
|
|
|
|
run_config(
|
|
|
|
run_config(
|
|
|
|
config_filename,
|
|
|
|
|
|
|
|
args.context,
|
|
|
|
args.context,
|
|
|
|
args.baseurl,
|
|
|
|
args.baseurl,
|
|
|
|
args.list_config,
|
|
|
|
args.list_config,
|
|
|
@ -684,7 +637,7 @@ def main() -> int:
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return 0
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
config = get_config(config_filename)
|
|
|
|
config = knotctl.get_config()
|
|
|
|
baseurl = config["baseurl"]
|
|
|
|
baseurl = config["baseurl"]
|
|
|
|
token = get_token(config)
|
|
|
|
token = get_token(config)
|
|
|
|
if token == "":
|
|
|
|
if token == "":
|
|
|
|