Add support for tsocks

This commit is contained in:
Micke Nordin 2024-11-06 15:43:01 +01:00
parent c674a02a1c
commit df681e23dc
Signed by: Micke
GPG key ID: 0DA0A7A5708FE257

View file

@ -19,7 +19,7 @@ import argcomplete
# To determine if openstack thinks that a given object exists already # To determine if openstack thinks that a given object exists already
def exists_in_openstack(output_error: tuple) -> bool: def exists_in_openstack(output_error: tuple) -> bool:
output = output_error[0] output = output_error[0]
#error = output_error[1] # error = output_error[1]
# FIXME: This is a dumb way to check that an object exists, we should check the error in addition to this # FIXME: This is a dumb way to check that an object exists, we should check the error in addition to this
try: try:
json.loads(output) json.loads(output)
@ -29,12 +29,11 @@ def exists_in_openstack(output_error: tuple) -> bool:
def get_dns_records(addresses: dict, fqdn: str) -> str: def get_dns_records(addresses: dict, fqdn: str) -> str:
def get_tabs(string: str) -> str: def get_tabs(string: str) -> str:
num_tabs: int = int(len(string.expandtabs()) / len(f"\t".expandtabs())) num_tabs: int = int(len(string.expandtabs()) / len(f"\t".expandtabs()))
tabs = str() tabs = str()
for _ in range(0, num_tabs): for _ in range(0, num_tabs):
tabs += '\t' tabs += "\t"
return tabs return tabs
v6_record = str() v6_record = str()
@ -42,7 +41,7 @@ def get_dns_records(addresses: dict, fqdn: str) -> str:
first = True first = True
tabs = get_tabs(f"{fqdn}.\t") tabs = get_tabs(f"{fqdn}.\t")
for address in addresses: for address in addresses:
if address.find('.') != -1: if address.find(".") != -1:
if first: if first:
v4_record = f"{fqdn}.\tA\t{address}\n" v4_record = f"{fqdn}.\tA\t{address}\n"
first = False first = False
@ -57,7 +56,7 @@ def get_dns_records(addresses: dict, fqdn: str) -> str:
# This function is responsible for collecting all neccessary information from the user, and provide feedback if something is missing # This function is responsible for collecting all neccessary information from the user, and provide feedback if something is missing
def get_options() -> dict: def get_options() -> dict:
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(title='subcommands', dest='command') subparsers = parser.add_subparsers(title="subcommands", dest="command")
# Used with the command "create" # Used with the command "create"
create_parser = subparsers.add_parser("create") create_parser = subparsers.add_parser("create")
@ -83,16 +82,14 @@ def get_options() -> dict:
) )
create_parser.add_argument( create_parser.add_argument(
"--sgroup-policy", "--sgroup-policy",
dest='sgroup_policy', dest="sgroup_policy",
help="Set security group policy for machine", help="Set security group policy for machine",
choices=[ choices=["affinity", "anti-affinity", "soft-affinity", "soft-anti-affinity"],
'affinity', 'anti-affinity', 'soft-affinity', 'soft-anti-affinity'
],
default="anti-affinity", default="anti-affinity",
) )
create_parser.add_argument( create_parser.add_argument(
"--volume-size", "--volume-size",
dest='volume_size', dest="volume_size",
help="Set volume size in GB for machine", help="Set volume size in GB for machine",
default="100", default="100",
) )
@ -100,24 +97,29 @@ def get_options() -> dict:
create_parser.add_argument( create_parser.add_argument(
"-k", "-k",
"--key", "--key",
help= help="SSH key to use, either the path to a public ssh key OR the name of an existing key in openstack",
"SSH key to use, either the path to a public ssh key OR the name of an existing key in openstack",
required=True, required=True,
) )
create_parser.add_argument( create_parser.add_argument(
"--fqdn", "--fqdn", help="fqdn of server, MUST follow name standard", required=True
help="fqdn of server, MUST follow name standard", )
required=True)
create_parser.add_argument( create_parser.add_argument(
'--format', "--format",
choices=['bind', 'json', 'shell', 'table', 'value', 'yaml'], choices=["bind", "json", "shell", "table", "value", "yaml"],
default="json", default="json",
) )
create_parser.add_argument( create_parser.add_argument(
"--namestandard", "--namestandard",
help="Name of name standard", help="Name of name standard",
default='default', default="default",
dest='namestandard', dest="namestandard",
)
create_parser.add_argument(
"--with-tsocks",
help="Run with tsocks",
action=argparse.BooleanOptionalAction,
default=False,
dest="with_tsocks",
) )
delete_parser = subparsers.add_parser("delete") delete_parser = subparsers.add_parser("delete")
@ -129,36 +131,43 @@ def get_options() -> dict:
delete_parser.add_argument( delete_parser.add_argument(
"--preserve-port", "--preserve-port",
action=argparse.BooleanOptionalAction, action=argparse.BooleanOptionalAction,
dest='preserve_port', dest="preserve_port",
help="Keep the configured port in openstack", help="Keep the configured port in openstack",
default=False, default=False,
) )
delete_parser.add_argument( delete_parser.add_argument(
"--preserve-cosmos-config", "--preserve-cosmos-config",
action=argparse.BooleanOptionalAction, action=argparse.BooleanOptionalAction,
dest='preserve_cosmos_overlay', dest="preserve_cosmos_overlay",
help="Keep the overlay for this server around", help="Keep the overlay for this server around",
default=False, default=False,
) )
delete_parser.add_argument( delete_parser.add_argument(
"--preserve-disk", "--preserve-disk",
action=argparse.BooleanOptionalAction, action=argparse.BooleanOptionalAction,
dest='preserve_disk', dest="preserve_disk",
help="Keep the configured disk in openstack", help="Keep the configured disk in openstack",
default=False, default=False,
) )
delete_parser.add_argument( delete_parser.add_argument(
"--namestandard", "--namestandard",
help="Name of name standard", help="Name of name standard",
default='default', default="default",
dest='namestandard', dest="namestandard",
)
delete_parser.add_argument(
"--with-tsocks",
help="Run with tsocks",
action=argparse.BooleanOptionalAction,
default=False,
dest="with_tsocks",
) )
show_parser = subparsers.add_parser("show") show_parser = subparsers.add_parser("show")
show_parser.add_argument( show_parser.add_argument(
'--format', "--format",
choices=['bind', 'json', 'shell', 'table', 'value', 'yaml'], choices=["bind", "json", "shell", "table", "value", "yaml"],
default='json', default="json",
dest='format', dest="format",
) )
show_parser.add_argument( show_parser.add_argument(
"--network", "--network",
@ -173,8 +182,15 @@ def get_options() -> dict:
show_parser.add_argument( show_parser.add_argument(
"--namestandard", "--namestandard",
help="Name of name standard", help="Name of name standard",
default='default', default="default",
dest='namestandard', dest="namestandard",
)
show_parser.add_argument(
"--with-tsocks",
help="Run with tsocks",
action=argparse.BooleanOptionalAction,
default=False,
dest="with_tsocks",
) )
argcomplete.autocomplete(parser) argcomplete.autocomplete(parser)
@ -182,163 +198,183 @@ def get_options() -> dict:
# This is an opinionated name standard that we follow, and WILL rely on for various automation tasks # This is an opinionated name standard that we follow, and WILL rely on for various automation tasks
fqdn = args.fqdn fqdn = args.fqdn
domain, environment, function, hostname, instance, location, number, service = parse_fqdn( domain, environment, function, hostname, instance, location, number, service = (
fqdn, args.namestandard) parse_fqdn(fqdn, args.namestandard)
)
# We will allways put a server in i server group, you can override the default with the --sgroup switch # We will allways put a server in i server group, you can override the default with the --sgroup switch
if ('sgroup' not in args) or (args.sgroup == ""): if ("sgroup" not in args) or (args.sgroup == ""):
# if it is not set, we will construct a security group name based on other information # if it is not set, we will construct a security group name based on other information
sgroup = fqdn.replace('.', '-') + "-sgroup" sgroup = fqdn.replace(".", "-").replace(number, "") + "sgroup"
else: else:
sgroup = args.sgroup sgroup = args.sgroup
# These options MUST match what is used in main function, or there WILL be dragons # These options MUST match what is used in main function, or there WILL be dragons
options: dict = { options: dict = {
'command': args.command, "command": args.command,
'domain': domain, "domain": domain,
'environment': environment, "environment": environment,
'fqdn': fqdn, "fqdn": fqdn,
'function': function, "function": function,
'hostname': hostname, "hostname": hostname,
'instance': instance, "instance": instance,
'location': location, "location": location,
'namestandard': args.namestandard, "namestandard": args.namestandard,
'number': number, "number": number,
'service': service, "service": service,
'sgroup': sgroup "sgroup": sgroup,
"with_tsocks": args.with_tsocks,
} }
if args.command == 'create': if args.command == "create":
options['format'] = args.format options["format"] = args.format
options['flavor'] = args.flavor options["flavor"] = args.flavor
options['image'] = args.image options["image"] = args.image
options['key'] = args.key options["key"] = args.key
options['network'] = args.network options["network"] = args.network
options['sgroup_policy'] = args.sgroup_policy options["sgroup_policy"] = args.sgroup_policy
options['volume_size'] = args.volume_size options["volume_size"] = args.volume_size
if args.command == 'delete': if args.command == "delete":
options['preserve_port'] = args.preserve_port options["preserve_port"] = args.preserve_port
options['preserve_cosmos_overlay'] = args.preserve_cosmos_overlay options["preserve_cosmos_overlay"] = args.preserve_cosmos_overlay
options['preserve_disk'] = args.preserve_disk options["preserve_disk"] = args.preserve_disk
if args.command == 'show': if args.command == "show":
options['format'] = args.format options["format"] = args.format
return options return options
def parse_fqdn(fqdn: str, namestandard: str) -> tuple: def parse_fqdn(fqdn: str, namestandard: str) -> tuple:
if namestandard == 'drive': if namestandard == "drive":
return parse_drive_fqdn(fqdn) return parse_drive_fqdn(fqdn)
else: else:
return parse_default_fqdn(fqdn) return parse_default_fqdn(fqdn)
def parse_default_fqdn(fqdn: str) -> tuple: def parse_default_fqdn(fqdn: str) -> tuple:
domain = '.'.join([x for x in fqdn.split('.')[:1]]) domain = ".".join([x for x in fqdn.split(".")[:1]])
hostname = fqdn.split('.')[0] hostname = fqdn.split(".")[0]
instance, location, environment, function, number = hostname.split('-') instance, location, environment, function, number = hostname.split("-")
service = fqdn.split('.')[1] service = fqdn.split(".")[1]
return domain, environment, function, hostname, instance, location, number, service return domain, environment, function, hostname, instance, location, number, service
def parse_drive_fqdn(fqdn: str) -> tuple: def parse_drive_fqdn(fqdn: str) -> tuple:
type_regex = r'-*[1-9]*\..*' type_regex = r"-*[1-9]*\..*"
server_type = re.sub(type_regex, '', fqdn) server_type = re.sub(type_regex, "", fqdn)
env_regex = r'.*(pilot|test).*' env_regex = r".*(pilot|test).*"
environment = re.sub(env_regex, r'\1', fqdn) environment = re.sub(env_regex, r"\1", fqdn)
domain = f'drive.{environment}.sunet.se' domain = f"drive.{environment}.sunet.se"
customer = 'common' customer = "common"
if environment not in ['pilot', 'test']: if environment not in ["pilot", "test"]:
environment = 'prod' environment = "prod"
domain = 'drive.sunet.se' domain = "drive.sunet.se"
if server_type in ["backup", "intern-db", "node", "redis", "script"]: if server_type in ["backup", "intern-db", "node", "redis", "script"]:
customer = fqdn.split('.')[1] customer = fqdn.split(".")[1]
if customer == 'drive': if customer == "drive":
customer = 'common' customer = "common"
elif server_type in ['gss', 'lookup']: elif server_type in ["gss", "lookup"]:
customer = server_type customer = server_type
elif server_type == 'gssbackup': elif server_type == "gssbackup":
customer = 'gss' customer = "gss"
elif server_type == 'lookupbackup': elif server_type == "lookupbackup":
customer = 'lookup' customer = "lookup"
else: else:
customer = 'common' customer = "common"
hostname = fqdn.split('.')[0] hostname = fqdn.split(".")[0]
number = re.sub(r'[-a-z.]', '', hostname) number = re.sub(r"[-a-z.]", "", hostname)
location = 'sto4' location = "sto4"
if number == '3': if number == "3":
location = 'sto3' location = "sto3"
if number == '1': if number == "1":
location = 'dco' location = "dco"
return domain, environment, server_type, hostname, customer, location, number, 'drive' return (
domain,
environment,
server_type,
hostname,
customer,
location,
number,
"drive",
)
def run_in_openstack(outer_command: list[str], rc_file: str) -> tuple: def run_in_openstack(
outer_command: list[str], rc_file: str, with_tsocks: bool
) -> tuple:
# This function runs the specified command with openstack cli using tsocks. # This function runs the specified command with openstack cli using tsocks.
# FIXME: We should support disabling tsocks with a commandline switch # FIXME: We should support disabling tsocks with a commandline switch
def run_command(inner_command: list[str]) -> tuple: def run_command(inner_command: list[str]) -> tuple:
proc = subprocess.Popen(inner_command, proc = subprocess.Popen(
stdin=subprocess.PIPE, inner_command,
stdout=subprocess.PIPE, stdin=subprocess.PIPE,
stderr=subprocess.PIPE, stdout=subprocess.PIPE,
text=True) stderr=subprocess.PIPE,
text=True,
)
output_error = proc.communicate() output_error = proc.communicate()
proc.wait() proc.wait()
return output_error return output_error
outer_command.insert(0, "openstack") outer_command.insert(0, "openstack")
outer_command.insert(0, 'tsocks') if with_tsocks:
outer_command.insert(0, "tsocks")
# This is where we actually use the openstack openrc file, and we source it before running the command # This is where we actually use the openstack openrc file, and we source it before running the command
string_cmd = f"bash -c 'source {rc_file} &&" string_cmd = f"bash -c 'source {rc_file} &&"
for cmd in outer_command: for cmd in outer_command:
string_cmd += ' ' + cmd string_cmd += " " + cmd
string_cmd += "'" string_cmd += "'"
full_command = shlex.split(string_cmd) full_command = shlex.split(string_cmd)
return run_command(full_command) return run_command(full_command)
def setup_key(in_key: str, rc_file: str) -> str: def setup_key(in_key: str, rc_file: str, with_tsocks: bool) -> str:
if type(in_key) == type(tuple()): if type(in_key) == type(tuple()):
key = in_key[0] key = in_key[0]
else: else:
key = in_key key = in_key
# We deal with public keys first, if the supplied option is a filename we will use that to create a new keypair in openstack if neccessary # We deal with public keys first, if the supplied option is a filename we will use that to create a new keypair in openstack if neccessary
# If the key is NOT a file on the local machine, we assume that it is a name of a pre existing key # If the key is NOT a file on the local machine, we assume that it is a name of a pre existing key
def keypair_existence(key_name: str) -> bool: def keypair_existence(key_name: str) -> bool:
show_keypair_command = ['keypair', 'show', '-f', 'json', key_name] show_keypair_command = ["keypair", "show", "-f", "json", key_name]
return exists_in_openstack( return exists_in_openstack(
run_in_openstack(show_keypair_command, rc_file)) run_in_openstack(show_keypair_command, rc_file, with_tsocks)
)
if isfile(key): if isfile(key):
key_name = str(os.environ.get('USER')) + '-sshkey' key_name = str(os.environ.get("USER")) + "-sshkey"
pub_key = key pub_key = key
create_keypair_command = [ create_keypair_command = [
'keypair', 'create', '--public-key', pub_key, key_name "keypair",
"create",
"--public-key",
pub_key,
key_name,
] ]
keypair_exists = keypair_existence(key_name) keypair_exists = keypair_existence(key_name)
if not keypair_exists: if not keypair_exists:
run_in_openstack(create_keypair_command, rc_file) run_in_openstack(create_keypair_command, rc_file, with_tsocks)
else: else:
key_name = key key_name = key
keypair_exists = keypair_existence(key_name) keypair_exists = keypair_existence(key_name)
if not keypair_exists: if not keypair_exists:
# We cannot proceed without a public key # We cannot proceed without a public key
print( print('{"ERROR": "No keypair exists and I could not create a new one :("}')
'{"ERROR": "No keypair exists and I could not create a new one :("}'
)
sys.exit(3) sys.exit(3)
return key_name return key_name
def setup_rc_file(options: dict) -> str: def setup_rc_file(options: dict) -> str:
config_basepath = path_join(path_join(os.environ["HOME"], ".config"), config_basepath = path_join(path_join(os.environ["HOME"], ".config"), "sunet")
"sunet")
rc_file = path_join( rc_file = path_join(
config_basepath, config_basepath,
f"app-cred-{options['service']}-{options['location']}-{options['environment']}-openrc.sh" f"app-cred-{options['service']}-{options['location']}-{options['environment']}-openrc.sh",
) )
if not isfile(rc_file): if not isfile(rc_file):
@ -349,21 +385,22 @@ def setup_rc_file(options: dict) -> str:
return rc_file return rc_file
def show_server(fqdn: str, rc_file: str, format: str = 'json') -> tuple: def show_server(
show_server_command = ['server', 'show', '-f', format, fqdn] fqdn: str, rc_file: str, with_tsocks: bool, format: str = "json"
return run_in_openstack(show_server_command, rc_file) ) -> tuple:
show_server_command = ["server", "show", "-f", format, fqdn]
return run_in_openstack(show_server_command, rc_file, with_tsocks)
def wait_for_server(fqdn: str, def wait_for_server(
rc_file: str, fqdn: str, rc_file: str, network: str, with_tsocks: bool, timeout=360
network: str, ) -> bool:
timeout=360) -> bool:
then = time.time() then = time.time()
now = then now = then
while then >= (now - timeout): while then >= (now - timeout):
try: try:
output, _ = show_server(fqdn, rc_file) output, _ = show_server(fqdn, rc_file, with_tsocks)
json.loads(output)['addresses'][network] json.loads(output)["addresses"][network]
return True return True
except KeyError: except KeyError:
time.sleep(3) time.sleep(3)
@ -377,128 +414,145 @@ def wait_for_server(fqdn: str,
def create(options: dict) -> int: def create(options: dict) -> int:
# All of these can be set by command line arguments, but some have defaults and as such are optional. # All of these can be set by command line arguments, but some have defaults and as such are optional.
# At this point they MUST be set after parsing args, otherwise there WILL be bugs # At this point they MUST be set after parsing args, otherwise there WILL be bugs
key: str = options['key'] key: str = options["key"]
dns_record: bool = False dns_record: bool = False
format: str = options['format'] format: str = options["format"]
if format == 'bind': if format == "bind":
format = 'json' format = "json"
dns_record = True dns_record = True
flavor: str = options['flavor'] flavor: str = options["flavor"]
fqdn: str = options['fqdn'] fqdn: str = options["fqdn"]
hostname: str = options['hostname'] hostname: str = options["hostname"]
image: str = options['image'] image: str = options["image"]
network: str = options['network'] network: str = options["network"]
rc_file: str = options['rc_file'] rc_file: str = options["rc_file"]
sgroup: str = options['sgroup'] sgroup: str = options["sgroup"]
sgroup_policy: str = options['sgroup_policy'] sgroup_policy: str = options["sgroup_policy"]
volume_size: str = options['volume_size'] volume_size: str = options["volume_size"]
with_tsocks: bool = options["with_tsocks"]
key_name: str = setup_key(key, rc_file) key_name: str = setup_key(key, rc_file, with_tsocks)
# FIXME: we don't support setting the portname, we just use the fqdn and append -port to it # FIXME: we don't support setting the portname, we just use the fqdn and append -port to it
port_name = options['fqdn'].replace('.', '-') + '-port' port_name = options["fqdn"].replace(".", "-") + "-port"
# Internal helper functions # Internal helper functions
def sgroup_show(sgroup: str) -> tuple: def sgroup_show(sgroup: str) -> tuple:
show_sgroup_command = ['server', 'group', 'show', '-f', 'json', sgroup] show_sgroup_command = ["server", "group", "show", "-f", "json", sgroup]
return run_in_openstack(show_sgroup_command, rc_file) return run_in_openstack(show_sgroup_command, rc_file, with_tsocks)
# Check if server exists # Check if server exists
server_output_error = show_server(fqdn, rc_file) server_output_error = show_server(fqdn, rc_file, with_tsocks)
server_exists = exists_in_openstack(server_output_error) server_exists = exists_in_openstack(server_output_error)
# We will bail out early if the server allready exists, and just print out what we know about it # We will bail out early if the server allready exists, and just print out what we know about it
if server_exists: if server_exists:
if dns_record: if dns_record:
addresses = json.loads( addresses = json.loads(server_output_error[0])["addresses"][network]
server_output_error[0])['addresses'][network]
print(get_dns_records(addresses, fqdn)) print(get_dns_records(addresses, fqdn))
else: else:
if format == 'json': if format == "json":
print(server_output_error[0]) print(server_output_error[0])
else: else:
print(show_server(fqdn, rc_file, format)[0]) print(show_server(fqdn, rc_file, with_tsocks, format)[0])
return 0 return 0
# Server group section # Server group section
sgroup_exists = exists_in_openstack(sgroup_show(sgroup)) sgroup_exists = exists_in_openstack(sgroup_show(sgroup))
if not sgroup_exists: if not sgroup_exists:
create_sgroup_command = [ create_sgroup_command = [
'server', 'group', 'create', '--policy', sgroup_policy, sgroup "server",
"group",
"create",
"--policy",
sgroup_policy,
sgroup,
] ]
run_in_openstack(create_sgroup_command, rc_file) run_in_openstack(create_sgroup_command, rc_file, with_tsocks)
sgroup_output, _ = sgroup_show(sgroup) sgroup_output, _ = sgroup_show(sgroup)
sgroup_object = json.loads(sgroup_output) sgroup_object = json.loads(sgroup_output)
sgroup_id = sgroup_object['id'] sgroup_id = sgroup_object["id"]
# Port section # Port section
show_port_command = ['port', 'show', '-f', 'json', port_name] show_port_command = ["port", "show", "-f", "json", port_name]
port_exists = exists_in_openstack( port_exists = exists_in_openstack(
run_in_openstack(show_port_command, rc_file)) run_in_openstack(show_port_command, rc_file, with_tsocks)
)
if not port_exists: if not port_exists:
create_port_command = [ create_port_command = ["port", "create", "--network", network, port_name]
'port', 'create', '--network', network, port_name run_in_openstack(create_port_command, rc_file, with_tsocks)
]
run_in_openstack(create_port_command, rc_file)
# Finaly set up is done, and we can create server # Finaly set up is done, and we can create server
create_server_command = [ create_server_command = [
'server', 'create', '--port', port_name, '--flavor', flavor, '--image', "server",
image, '--boot-from-volume', volume_size, '--key-name', key_name, "create",
'--hint', f'group={sgroup_id}', fqdn "--port",
port_name,
"--flavor",
flavor,
"--image",
image,
"--boot-from-volume",
volume_size,
"--key-name",
key_name,
"--hint",
f"group={sgroup_id}",
fqdn,
] ]
run_in_openstack(create_server_command, rc_file) run_in_openstack(create_server_command, rc_file, with_tsocks)
timeout = 360 timeout = 360
succeed = wait_for_server(fqdn, rc_file, network, timeout=timeout) succeed = wait_for_server(fqdn, rc_file, network, with_tsocks, timeout=timeout)
if not succeed: if not succeed:
print(f"Wait for server: {fqdn} timed out in {timeout}") print(f"Wait for server: {fqdn} timed out in {timeout}")
return 4 return 4
if dns_record: if dns_record:
output, _ = show_server(fqdn, rc_file) output, _ = show_server(fqdn, rc_file, with_tsocks)
addresses = json.loads(output)['addresses'][network] addresses = json.loads(output)["addresses"][network]
print(get_dns_records(addresses, fqdn)) print(get_dns_records(addresses, fqdn))
else: else:
print(show_server(fqdn, rc_file, format)) print(show_server(fqdn, rc_file, with_tsocks, format))
return 0 return 0
def delete(options: dict) -> int: def delete(options: dict) -> int:
fqdn = options['fqdn'] fqdn = options["fqdn"]
rc_file = options['rc_file'] rc_file = options["rc_file"]
preserve_port = options['preserve_port'] preserve_port = options["preserve_port"]
preserve_cosmos_overlay = options['preserve_cosmos_overlay'] preserve_cosmos_overlay = options["preserve_cosmos_overlay"]
preserve_disk = options['preserve_disk'] preserve_disk = options["preserve_disk"]
with_tsocks = options["with_tsocks"]
# Check if server exists # Check if server exists
server_output_error = show_server(fqdn, rc_file) server_output_error = show_server(fqdn, rc_file, with_tsocks)
server_exists = exists_in_openstack(server_output_error) server_exists = exists_in_openstack(server_output_error)
# We will bail out early if the server does not allready exists # We will bail out early if the server does not allready exists
if not server_exists: if not server_exists:
print(f"No server called {fqdn} exists.") print(f"No server called {fqdn} exists.")
return 0 return 0
delete_server_command = ['server', 'delete', fqdn] delete_server_command = ["server", "delete", fqdn]
run_in_openstack(delete_server_command, rc_file) run_in_openstack(delete_server_command, rc_file, with_tsocks)
print(f"Deleted server: {fqdn}") print(f"Deleted server: {fqdn}")
if not preserve_disk: if not preserve_disk:
server_object = json.loads(server_output_error[0]) server_object = json.loads(server_output_error[0])
for disk in server_object['volumes_attached']: for disk in server_object["volumes_attached"]:
delete_disk_command = ['volume', 'delete', disk['id']] delete_disk_command = ["volume", "delete", disk["id"]]
run_in_openstack(delete_disk_command, rc_file) run_in_openstack(delete_disk_command, rc_file, with_tsocks)
# Port section # Port section
if not preserve_port: if not preserve_port:
# FIXME: we don't support setting the portname, we just use the fqdn and append -port to it # FIXME: we don't support setting the portname, we just use the fqdn and append -port to it
port_name = options['fqdn'].replace('.', '-') + '-port' port_name = options["fqdn"].replace(".", "-") + "-port"
show_port_command = ['port', 'show', '-f', 'json', port_name] show_port_command = ["port", "show", "-f", "json", port_name]
port_exists = exists_in_openstack( port_exists = exists_in_openstack(
run_in_openstack(show_port_command, rc_file)) run_in_openstack(show_port_command, rc_file, with_tsocks)
)
if port_exists: if port_exists:
delete_port_command = ['port', 'delete', port_name] delete_port_command = ["port", "delete", port_name]
run_in_openstack(delete_port_command, rc_file) run_in_openstack(delete_port_command, rc_file, with_tsocks)
print(f"Deleted port: {port_name}") print(f"Deleted port: {port_name}")
dir = os.path.dirname(os.path.abspath(__file__)) dir = os.path.dirname(os.path.abspath(__file__))
overlay = path_join(dir, fqdn) overlay = path_join(dir, fqdn)
@ -509,29 +563,34 @@ def delete(options: dict) -> int:
def show(options: dict) -> None: def show(options: dict) -> None:
if options['format'] == 'bind': if options["format"] == "bind":
# We assume that only public addresses go in dns # We assume that only public addresses go in dns
addresses = json.loads( addresses = json.loads(
show_server(options['fqdn'], show_server(options["fqdn"], options["rc_file"], options["with_tsocks"])[0]
options['rc_file'])[0])['addresses']['public'] )["addresses"]["public"]
print(get_dns_records(addresses, options['fqdn'])) print(get_dns_records(addresses, options["fqdn"]))
else: else:
print( print(
show_server(options['fqdn'], options['rc_file'], show_server(
options['format'])) options["fqdn"],
options["rc_file"],
options["with_tsocks"],
options["format"],
)
)
def main() -> int: def main() -> int:
# Make sure we have openstack app credentials matching the naming scheme <service>-<location>-<environment> # Make sure we have openstack app credentials matching the naming scheme <service>-<location>-<environment>
options = get_options() options = get_options()
options['rc_file'] = setup_rc_file(options) options["rc_file"] = setup_rc_file(options)
command = options['command'] command = options["command"]
if command == 'create': if command == "create":
return create(options) return create(options)
if command == 'delete': if command == "delete":
return delete(options) return delete(options)
if command == 'show': if command == "show":
show(options) show(options)
return 0 return 0