Rename InvirtException to more descriptive PathResolutionException
[invirt/packages/invirt-base.git] / scripts / invirt-getconf
1 #!/usr/bin/env python3
2
3 """
4 invirt-getconf loads an invirt configuration file (either the original YAML
5 source or the faster-to-load JSON cache) and prints the configuration option
6 with the given name (key).  Keys are dot-separated paths into the YAML
7 configuration tree.  List indexes (0-based) are also treated as path
8 components.
9
10 (Due to this path language, certain restrictions are placed on the keys used in
11 the YAML configuration; e.g., they cannot contain dots.)
12
13 Examples:
14
15   invirt-getconf db.uri
16   invirt-getconf hosts.0.ip
17 """
18
19 import argparse
20 import sys
21 import yaml
22
23 import invirt
24
25
26 class PathResolutionException(Exception):
27     pass
28
29
30 def main():
31     parser = argparse.ArgumentParser(description='Get values from invirt configuration file')
32     parser.add_argument('-r', '--refresh', action='store_true', help='Force regenerate the cache')
33     parser.add_argument('-l', '--ls', action='store_true', help='List children of node')
34     parser.add_argument('path', nargs='?', default='', help='Path of value to get')
35
36     args = parser.parse_args()
37
38     components = args.path.split('.')
39
40     conf = invirt.config.load(args.refresh)
41     for i, component in enumerate(components):
42         progress = '.'.join(components[:i])
43
44         if isinstance(conf, list):
45             try:
46                 component = int(component)
47             except ValueError:
48                 raise PathResolutionException(f'{progress}: node is a list; integer path component required, '
49                                       'but got "{component}"')
50
51             try:
52                 conf = conf[component]
53             except IndexError:
54                 raise PathResolutionException(f'{progress}: index {component} out of range')
55         elif isinstance(conf, dict):
56             try:
57                 conf = conf[component]
58             except KeyError:
59                 raise PathResolutionException(f'{progress}: key "{component}" not found')
60         else:
61             raise PathResolutionException(f'{progress}: node has no children (atomic datum)')
62
63     if args.ls:
64         if isinstance(conf, list):
65             for i in range(len(conf)):
66                 print(i)
67         elif isinstance(conf, dict):
68             for k in conf:
69                 print(k)
70         else:
71             raise PathResolutionException(f'{".".join(components)}: node has no children (atomic datum)')
72     else:
73         if isinstance(conf, (dict, list)):
74             print(conf)
75         else:
76             yaml.dump(conf, sys.stdout, Dumper=yaml.CSafeDumper, default_flow_style=False)
77
78
79 if __name__ == '__main__':
80     main()