Le fichier JSON qui reçoit le fichier de paramètres et est généré par jinja2 est utilisé lors du déploiement. Je veux vérifier si ce fichier JSON généré est un JSON valide.
Une image comme j2cli.
Utilisez les deux fichiers suivants.
--Fichier de configuration (.json)
Par exemple, lorsque le fichier de paramètres est le suivant
{
"name": "staging"
}
Utilisez un modèle comme celui-ci.
{
"app-name": "{{name}}-app",
"batch-name": "{{name}}-batch"
}
Par conséquent, le JSON suivant est généré. Ceci est utilisé comme fichier de configuration réel.
{
"app-name": "staging-app",
"batch-name": "staging-batch"
}
Dans le cas de paramètres de type dev, la sortie peut être la suivante.
{
"app-name": "dev-app",
"batch-name": "dev-batch"
}
Le JSON généré est peut-être invalide. Il semble que vous le remarquerez enfin lorsqu'il sera déployé en production. Je veux vérifier à l'avance.
La politique est la suivante.
Cela ressemble à ceci dans le code python.
import jinja2
import json
env = jinja2.Environment(loader=jinja2.FileSystemLoader(["."]), undefined=jinja2.StrictUndefined)
t = env.get_or_select_template(template_path)
json.loads(t.render(**config)) #Erreur si invalide
Cependant, il y a quelques mises en garde.
{"foo": "foo-{{name}}"}
Si vous émettez avec jinja2 sans rien définir dans un tel modèle, ce qui suit se produira, mais aucune erreur ne se produira.
{"foo": "foo-"}
Cela peut être détecté en modifiant le paramètre non défini de jinja2. Si vous ajoutez ʻundefined = jinja2.StrictUndefined, ʻUndefinedError
se produira.
C'est mauvais si le modèle est défectueux et contient une quantité excessive de "}". Bien que le JSON généré soit valide en tant que JSON. Pas le résultat attendu.
Si vous écrivez accidentellement le modèle suivant.
{
"app-name": "{{name}}}-app"
}
Ce qui suit est un JSON valide. Pas le résultat attendu.
{
"app-name": "staging}-app"
}
Pour le moment, vous devriez également vérifier la valeur de dict.
Sur la base de ce qui précède, j'ai créé un script qui vérifie si le résultat de l'émission avec jinja2 est un JSON valide. Utilisez-le comme ça. Si la variable environ n'existe pas, une erreur se produira comme indiqué ci-dessous. Un exemple d'utilisation de ceci est une erreur lorsque deux paramètres nommés ʻenviron` n'existent pas dans le fichier de paramètres.
$ python check.py --conf-dir conf/ --template-dir template/ || echo ng
template/back.json.j2(conf/master.json): UndefinedError 'environ' is undefined
template/back.json.j2(conf/production.json): UndefinedError 'environ' is undefined
template/back.json.j2(conf/rook.json): UndefinedError 'environ' is undefined
ng
La mise en œuvre est la suivante.
import sys
import os.path
import argparse
import jinja2
import json
def validate_conf(d, path=None):
path = path or []
if hasattr(d, "items"):
for k, v in d.items():
path.append(k)
validate_conf(v, path=path)
path.pop()
elif isinstance(d, (list, tuple)):
for i, x in enumerate(d):
path.append(i)
validate_conf(x, path=path)
path.pop()
elif isinstance(d, str):
v = d
if "{" in v:
raise ValueError("invalid value: '{{' is included. path={}".format(path))
if "}" in v:
raise ValueError("invalid value: '}}' is included. path={}".format(path))
return d
def check(env, config, template_path):
t = env.get_or_select_template(template_path)
data = json.loads(t.render(**config))
return validate_conf(data)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--conf-dir", required=True)
parser.add_argument("--template-dir", required=True)
args = parser.parse_args()
env = jinja2.Environment(loader=jinja2.FileSystemLoader(["."]), undefined=jinja2.StrictUndefined)
status = 0
for root, _, conf_files in os.walk(args.conf_dir):
for conf_file in conf_files:
try:
confpath = os.path.join(root, conf_file)
with open(confpath) as rf:
conf = json.load(rf)
except Exception as e:
sys.stderr.write("{confpath}: {e.__class__.__name__} {e}\n".format(confpath=confpath, e=e))
status = 1
continue
for root2, _, template_files in os.walk(args.template_dir):
for template_file in template_files:
try:
filepath = os.path.join(root2, template_file)
check(env, conf, filepath)
except Exception as e:
sys.stderr.write("{filepath}({confpath}): {e.__class__.__name__} {e}\n".format(
confpath=confpath, filepath=filepath, e=e)
)
status = 1
sys.exit(status)
if __name__ == "__main__":
main()
Recommended Posts