Merge pull request #664 from yosoyjay/add-variables-to-config-keys

Add ability to use variables in config dictionary keys
This commit is contained in:
Jesse Lopez 2022-09-15 11:20:58 -07:00 коммит произвёл GitHub
Родитель 5e7133773f 83520aecbf
Коммит ac33a7f38b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 51 добавлений и 24 удалений

Просмотреть файл

@ -1,3 +1,4 @@
import copy
import json
import os
import re
@ -14,14 +15,17 @@ class ConfigFile:
self.data = {}
self.regex = re.compile(r'({{([^{}]*)}})')
def open(self, fname):
def open(self, fname, preprocess=True, preprocess_extended=False):
log.debug("opening "+fname)
self.file_location = os.path.dirname(fname)
if self.file_location == "":
self.file_location = "."
with open(fname) as f:
self.data = json.load(f)
if preprocess:
self.data = self.preprocess(extended=preprocess_extended)
def save(self, fname):
with open(fname, "w") as f:
json.dump(self.data, f, indent=4)
@ -36,11 +40,27 @@ class ConfigFile:
dest = azutil.get_vm_private_ip(self.read_value("resource_group"), install_from)
log.debug(f"install_from destination : {dest}")
return dest
def __evaluate_dict(self, x, extended):
# Create deep copy of dict to avoid unintentionally deleting items if variables are used in keys
x = copy.deepcopy(x)
ret = {}
updated_keys = []
for k in x.keys():
ret[k] = self.__evaluate(x[k], extended)
# Update key names if config variable (i.e. {{variables.key}} ) used
if "variables." in k:
log.debug(f"expanding key {k}")
new_key = self.__evaluate(k, extended)
ret[new_key] = self.__evaluate(x[k], extended)
updated_keys.append(k)
else:
ret[k] = self.__evaluate(x[k], extended)
# Delete keys from dict that were updated
# - Not doing so can result in duplicate fields in deploy_*json
if updated_keys:
for old_key in updated_keys:
del x[old_key]
return ret
def __evaluate_list(self, x, extended):
@ -77,10 +97,10 @@ class ConfigFile:
except KeyError:
log.error("read_keys : "+v+" not in config")
sys.exit(1)
if type(it) is not dict:
log.error("read_keys : "+v+" is not a dict")
keys = list(it.keys())
log.debug("read_keys (exit): keys("+v+")="+",".join(keys))
return keys
@ -100,7 +120,7 @@ class ConfigFile:
else:
log.error("invalid path in config file ({v})")
it = it[x]
if type(it) is str:
res = self.process_value(it)
else:
@ -108,7 +128,7 @@ class ConfigFile:
except KeyError:
log.debug(f"using default value ({default})")
res = default
log.debug("read_value (exit): "+v+"="+str(res))
return res
@ -118,9 +138,9 @@ class ConfigFile:
def repl(match):
return str(self.process_value(match.group()[2:-2], extended))
v = self.regex.sub(lambda m: str(self.process_value(m.group()[2:-2], extended)), v)
parts = v.split('.')
prefix = parts[0]
if len(parts) == 1:
@ -186,6 +206,6 @@ class ConfigFile:
res = f.read()
else:
res = v
log.debug("process_value (exit): "+str(v)+"="+str(res))
return res

Просмотреть файл

@ -1,4 +1,5 @@
import argparse
import copy
import datetime
import json
import os
@ -8,7 +9,10 @@ import socket
import sys
import textwrap
import time
import copy
from cryptography.hazmat.backends import default_backend as crypto_default_backend
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import arm
import azconfig
@ -16,10 +20,6 @@ import azinstall
import azlog
import azutil
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend as crypto_default_backend
log = azlog.getLogger(__name__)
def do_preprocess(args):
@ -203,7 +203,7 @@ def do_connect(args):
sshuser = adminuser
else:
sshuser = args.user
sshport = c.read_value("ssh_port", 22)
jumpbox = c.read_value("install_from")
@ -470,7 +470,7 @@ def _wait_for_deployment(resource_group, deploy_name):
elif isinstance(value, list):
wrapped_print(indent, str(key))
pretty_print(value, indent+4)
else:
else:
wrapped_print(indent, f"{key}: {value}")
else:
wrapped_print(indent, str(d))
@ -565,8 +565,8 @@ def do_slurm_resume(args):
# first get the resource name
resource_names, resource_list = _nodelist_expand(args.nodes)
# Create a copy of the configuration to use as template
# for the final deployment configuration
# Create a copy of the configuration to use as template
# for the final deployment configuration
config = copy.deepcopy(config_orig)
config["resources"] = {}
@ -716,7 +716,7 @@ def do_run_install(args):
if os.path.isdir(tmpdir):
log.debug("removing existing tmp directory")
shutil.rmtree(tmpdir)
adminuser = config["admin_user"]
private_key_file = adminuser+"_id_rsa"
public_key_file = adminuser+"_id_rsa.pub"
@ -914,7 +914,7 @@ if __name__ == "__main__":
preprocess_parser.set_defaults(func=do_preprocess)
run_parser = subparsers.add_parser(
"run",
"run",
parents=[gopt_parser],
add_help=False,
description="run a command on the specified resources",
@ -940,7 +940,7 @@ if __name__ == "__main__":
)
scp_parser = subparsers.add_parser(
"scp",
"scp",
parents=[gopt_parser],
add_help=False,
description="secure copy",

Просмотреть файл

@ -20,5 +20,8 @@ class TestConfigFile(unittest.TestCase):
def test_replace_double_curly_braces(self):
self.assertEqual(self.config.read_value("double_curly_braces"), "simple_variable=42")
def test_replace_in_dict_key(self):
self.assertEqual(self.config.read_value("resources.foo"), "bar")
if __name__ == "__main__":
unittest.main()

Просмотреть файл

@ -4,6 +4,10 @@
"use_variable": "variables.simple_variable",
"double_curly_braces": "simple_variable={{variables.simple_variable}}",
"variables": {
"simple_variable": 42
"simple_variable": 42,
"resource_name": "foo"
},
"resources": {
"variables.resource_name": "bar"
}
}