|  | #!/usr/bin/python | 
|  |  | 
|  | from __future__ import print_function | 
|  |  | 
|  | import argparse | 
|  | import os | 
|  | import sys | 
|  | import yaml | 
|  |  | 
|  | def _merge_items(a, b, path=None): | 
|  | """Merge b into a""" | 
|  | if path is None: path = [] | 
|  | for key in b: | 
|  | if key in a: | 
|  | if isinstance(a[key], dict) and isinstance(b[key], dict): | 
|  | _merge_items(a[key], b[key], path + [str(key)]) | 
|  | elif a[key] == b[key]: | 
|  | pass # same leaf value | 
|  | else: | 
|  | raise Exception('Conflict at %s' % '.'.join(path + [str(key)])) | 
|  | else: | 
|  | a[key] = b[key] | 
|  | return a | 
|  |  | 
|  | def repo_add(content, name, source, pin_priority=None): | 
|  | """Adds repo dict to provided content""" | 
|  | t = {} | 
|  | r = {name: {'architectures': 'amd64', | 
|  | 'source': source}} | 
|  | if pin_priority: | 
|  | r[name]['pin'] = [{'package': '*', | 
|  | 'priority': pin_priority, | 
|  | 'pin': 'release o=Ubuntu'}] | 
|  | t['parameters'] = {'linux': {'system': {'repo': r}}} | 
|  | _merge_items(content, t) | 
|  |  | 
|  | def main(): | 
|  | parser = argparse.ArgumentParser(description='Update reclass model for specific node') | 
|  | parser.add_argument('--node', | 
|  | type=str, | 
|  | help='FQDN of the node to update.') | 
|  | parser.add_argument('--node-path', | 
|  | type=str, | 
|  | default='/srv/salt/reclass/nodes/_generated', | 
|  | help='Path to directory with the nodes.') | 
|  | subparsers = parser.add_subparsers() | 
|  |  | 
|  |  | 
|  | # create the parser for the "add" command | 
|  | parser_add = subparsers.add_parser('repo_add', help='Add a new repo.') | 
|  | parser_add.set_defaults(command='repo_add') | 
|  | parser_add.add_argument('--repo-name', | 
|  | type=str, | 
|  | required=True, | 
|  | help='The name of the repo to add.') | 
|  | parser_add.add_argument('--source', | 
|  | type=str, | 
|  | required=True, | 
|  | help='The source link of the repo. For example: ' | 
|  | 'deb http://my.repo.com/xenial ocata main') | 
|  | parser_add.add_argument('--priority', | 
|  | type=int, | 
|  | help='The pin priority of the repo.') | 
|  | args = parser.parse_args() | 
|  |  | 
|  | if args.node: | 
|  | node_files = ['%s/%s.yml' % (args.node_path, args.node)] | 
|  | else: | 
|  |  | 
|  | node_files = ['%s/%s' % (args.node_path, f) for f in os.listdir(args.node_path) if f.endswith('.yml')] | 
|  |  | 
|  | # check we can read the file | 
|  | for node_file in node_files: | 
|  | node_name = os.path.basename(node_file)[:-4] | 
|  | if not os.access(node_file, os.W_OK): | 
|  | print("Can not write to nodes file %s" % node_file, file=sys.stderr) | 
|  | sys.exit(1) | 
|  |  | 
|  | try: | 
|  | content = {} | 
|  | with open(node_file) as f: | 
|  | content = yaml.load(f) | 
|  |  | 
|  | if args.command == 'repo_add': | 
|  | print("Adding repo to the node: %s" % node_name) | 
|  | repo_add(content, args.repo_name, args.source, args.priority) | 
|  |  | 
|  | with open(node_file, "w") as f: | 
|  | yaml.dump(content, f, default_flow_style=False) | 
|  | print("Node: %s has been updated successfully." % node_name) | 
|  |  | 
|  | except Exception as e: | 
|  | print(e, file=sys.stderr) | 
|  | sys.exit(1) | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | main() |