def cli(): try: inventory_dir = os.path.abspath(os.path.dirname(sys.argv[0])) defaults = {'pretty_print' : True, 'output' : 'yaml', 'inventory_base_uri': inventory_dir } defaults.update(find_and_read_configfile()) options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, inventory_shortopt='-t', inventory_longopt='--top', inventory_help='output the state tops (inventory)', nodeinfo_shortopt='-p', nodeinfo_longopt='--pillar', nodeinfo_dest='nodename', nodeinfo_help='output pillar data for a specific node', defaults=defaults) if options.mode == MODE_NODEINFO: data = ext_pillar(options.nodename, {}, storage_type=options.storage_type, inventory_base_uri=options.inventory_base_uri, nodes_uri=options.nodes_uri, classes_uri=options.classes_uri) else: data = top(minion_id=None, storage_type=options.storage_type, inventory_base_uri=options.inventory_base_uri, nodes_uri=options.nodes_uri, classes_uri=options.classes_uri) print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def main(): try: defaults = {'pretty_print' : OPT_PRETTY_PRINT, 'output' : OPT_OUTPUT } defaults.update(find_and_read_configfile()) options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, defaults=defaults) storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri, default_environment='base') class_mappings = defaults.get('class_mappings') reclass = Core(storage, class_mappings) sys.path.append(options.inventory_base_uri) if options.mode == MODE_NODEINFO: data = reclass.nodeinfo(options.nodename) else: data = reclass.inventory() print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def inventory(**connection_args): ''' Get all nodes in inventory and their associated services/roles classification. CLI Examples: .. code-block:: bash salt '*' reclass.inventory ''' defaults = find_and_read_configfile() storage = get_storage(defaults['storage_type'], _get_nodes_dir(), _get_classes_dir()) reclass = Core(storage, None) nodes = reclass.inventory()["nodes"] output = {} for node in nodes: service_classification = [] role_classification = [] for service in nodes[node]['parameters']: if service not in ['_param', 'private_keys', 'public_keys', 'known_hosts']: service_classification.append(service) for role in nodes[node]['parameters'][service]: if role not in ['_support', '_orchestrate', 'common']: role_classification.append('%s.%s' % (service, role)) output[node] = { 'roles': role_classification, 'services': service_classification, } return output
def __init__(self, nodes_uri, classes_uri, default_environment=None): super(ExternalNodeStorage, self).__init__(STORAGE_NAME) self.backends = find_and_read_configfile().get( 'multi_fs', ['yaml_fs', 'remote_fs']) def name_mangler(relpath, name): # nodes are identified just by their basename, so # no mangling required return relpath, name self._nodes_uri = nodes_uri self._nodes = self._enumerate_inventory(nodes_uri, name_mangler) def name_mangler(relpath, name): if relpath == '.': # './' is converted to None return None, name parts = relpath.split(os.path.sep) if name != 'init': # "init" is the directory index, so only append the basename # to the path parts for all other filenames. This has the # effect that data in file "foo/init.yml" will be registered # as data for class "foo", not "foo.init" parts.append(name) return relpath, '.'.join(parts) self._classes_uri = classes_uri self._classes = self._enumerate_inventory(classes_uri, name_mangler) self._default_environment = default_environment
def cli(): try: inventory_dir = os.path.abspath(os.path.dirname(sys.argv[0])) defaults = { "pretty_print": True, "output": "yaml", "inventory_base_uri": inventory_dir, "file_extension": OPT_SALT_FILE_EXTENSION, } defaults.update(find_and_read_configfile()) options = get_options( RECLASS_NAME, VERSION, DESCRIPTION, inventory_shortopt="-t", inventory_longopt="--top", inventory_help="output the state tops (inventory)", nodeinfo_shortopt="-p", nodeinfo_longopt="--pillar", nodeinfo_dest="nodename", nodeinfo_help="output pillar data for a specific node", defaults=defaults, ) class_mappings = defaults.get("class_mappings") if options.mode == MODE_NODEINFO: data = ext_pillar( options.nodename, {}, storage_type=options.storage_type, inventory_base_uri=options.inventory_base_uri, nodes_uri=options.nodes_uri, classes_uri=options.classes_uri, file_extension=options.file_extension, class_mappings=class_mappings, ) else: data = top( minion_id=None, storage_type=options.storage_type, inventory_base_uri=options.inventory_base_uri, nodes_uri=options.nodes_uri, classes_uri=options.classes_uri, file_extension=options.file_extension, class_mappings=class_mappings, ) print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def main(): try: defaults = {'pretty_print' : OPT_PRETTY_PRINT, 'output' : OPT_OUTPUT } defaults.update(find_and_read_configfile()) options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, defaults=defaults) if options.mode == MODE_NODEINFO: data = get_nodeinfo(options.storage_type, options.inventory_base_uri, options.nodes_uri, options.classes_uri, options.nodename) else: data = get_inventory(options.storage_type, options.inventory_base_uri, options.nodes_uri, options.classes_uri) print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def cli(): try: # this adapter has to be symlinked to ansible_dir, so we can use this # information to initialise the inventory_base_uri to ansible_dir: ansible_dir = os.path.abspath(os.path.dirname(sys.argv[0])) defaults = {'inventory_base_uri': ansible_dir, 'pretty_print' : True, 'output' : 'json', 'applications_postfix': '_hosts', 'no_meta': True } defaults.update(find_and_read_configfile()) sys.path.append(ansible_dir) def add_ansible_options_group(parser, defaults): group = optparse.OptionGroup(parser, 'Ansible options', 'Ansible-specific options') group.add_option('--applications-postfix', dest='applications_postfix', default=defaults.get('applications_postfix'), help='postfix to append to applications to '\ 'turn them into groups') parser.add_option_group(group) options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, inventory_shortopt='-l', inventory_longopt='--list', inventory_help='output the inventory', nodeinfo_shortopt='-t', nodeinfo_longopt='--host', nodeinfo_dest='hostname', nodeinfo_help='output host_vars for the given host', add_options_cb=add_ansible_options_group, defaults=defaults) storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri) class_mappings = defaults.get('class_mappings') no_meta = defaults.get('no_meta') reclass = Core(storage, class_mappings) if options.mode == MODE_NODEINFO: data = node_to_node(reclass.nodeinfo(options.hostname)) else: data = reclass.inventory() # Ansible inventory is only the list of groups. Groups are the set # of classes plus the set of applications with the postfix added: groups = data['classes'] apps = data['applications'] if options.applications_postfix: postfix = options.applications_postfix groups.update([(k + postfix, v) for k, v in apps.iteritems()]) else: groups.update(apps) if no_meta: data = groups else: hostvars = dict() for node, nodeinfo in data['nodes'].items(): hostvars[node] = node_to_node(nodeinfo) data = groups data['_meta'] = {'hostvars': hostvars} print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def _get_classes_dir(): defaults = find_and_read_configfile() return os.path.join(defaults.get('inventory_base_uri'), 'classes')
def _get_nodes_dir(): defaults = find_and_read_configfile() return defaults.get('nodes_uri') or \ os.path.join(defaults.get('inventory_base_uri'), 'nodes')
def cli(): try: # this adapter has to be symlinked to ansible_dir, so we can use this # information to initialise the inventory_base_uri to ansible_dir: ansible_dir = os.path.abspath(os.path.dirname(sys.argv[0])) defaults = { 'inventory_base_uri': ansible_dir, 'pretty_print': True, 'output': 'json', 'applications_postfix': '_hosts', 'no_meta': True } defaults.update(find_and_read_configfile()) sys.path.append(ansible_dir) def add_ansible_options_group(parser, defaults): group = optparse.OptionGroup(parser, 'Ansible options', 'Ansible-specific options') group.add_option('--applications-postfix', dest='applications_postfix', default=defaults.get('applications_postfix'), help='postfix to append to applications to '\ 'turn them into groups') parser.add_option_group(group) options = get_options( RECLASS_NAME, VERSION, DESCRIPTION, inventory_shortopt='-l', inventory_longopt='--list', inventory_help='output the inventory', nodeinfo_shortopt='-t', nodeinfo_longopt='--host', nodeinfo_dest='hostname', nodeinfo_help='output host_vars for the given host', add_options_cb=add_ansible_options_group, defaults=defaults) storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri) class_mappings = defaults.get('class_mappings') no_meta = defaults.get('no_meta') reclass = Core(storage, class_mappings) if options.mode == MODE_NODEINFO: data = node_to_node(reclass.nodeinfo(options.hostname)) else: data = reclass.inventory() # Ansible inventory is only the list of groups. Groups are the set # of classes plus the set of applications with the postfix added: groups = data['classes'] apps = data['applications'] if options.applications_postfix: postfix = options.applications_postfix groups.update([(k + postfix, v) for k, v in apps.iteritems()]) else: groups.update(apps) if no_meta: data = groups else: hostvars = dict() for node, nodeinfo in data['nodes'].items(): hostvars[node] = node_to_node(nodeinfo) data = groups data['_meta'] = {'hostvars': hostvars} print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def cli(): try: # this adapter has to be symlinked to ansible_dir, so we can use this # information to initialise the inventory_base_uri to ansible_dir: ansible_dir = os.path.abspath(os.path.dirname(sys.argv[0])) defaults = { 'inventory_base_uri': ansible_dir, 'no_refs': False, 'pretty_print': True, 'output': 'json', 'applications_postfix': '_hosts' } defaults.update(find_and_read_configfile()) def add_ansible_options_group(parser, defaults): group = optparse.OptionGroup(parser, 'Ansible options', 'Ansible-specific options') group.add_option('--applications-postfix', dest='applications_postfix', default=defaults.get('applications_postfix'), help='postfix to append to applications to '\ 'turn them into groups') parser.add_option_group(group) options = get_options( RECLASS_NAME, VERSION, DESCRIPTION, inventory_shortopt='-l', inventory_longopt='--list', inventory_help='output the inventory', nodeinfo_shortopt='-t', nodeinfo_longopt='--host', nodeinfo_dest='hostname', nodeinfo_help='output host_vars for the given host', add_options_cb=add_ansible_options_group, defaults=defaults) storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri, options.compose_node_name) class_mappings = defaults.get('class_mappings') defaults.update(vars(options)) settings = Settings(defaults) reclass = Core(storage, class_mappings, settings) if options.mode == MODE_NODEINFO: data = reclass.nodeinfo(options.hostname) # Massage and shift the data like Ansible wants it data['parameters']['__reclass__'] = data['__reclass__'] for i in ('classes', 'applications'): data['parameters']['__reclass__'][i] = data[i] data = data['parameters'] else: data = reclass.inventory() # Ansible inventory is only the list of groups. Groups are the set # of classes plus the set of applications with the postfix added: groups = data['classes'] apps = data['applications'] if options.applications_postfix: postfix = options.applications_postfix groups.update([(k + postfix, v) for (k, v) in iteritems(apps)]) else: groups.update(apps) data = groups print( output(data, options.output, options.pretty_print, options.no_refs)) except ReclassException as e: e.exit_with_message(sys.stderr) sys.exit(posix.EX_OK)
def cli(): try: # this adapter has to be symlinked to ansible_dir, so we can use this # information to initialise the inventory_base_uri to ansible_dir: ansible_dir = os.path.abspath(os.path.dirname(sys.argv[0])) defaults = {'inventory_base_uri': ansible_dir, 'pretty_print' : True, 'output' : 'json', 'applications_postfix': '_hosts', 'file_extension': OPT_ANSIBLE_FILE_EXTENSION } defaults.update(find_and_read_configfile()) def add_ansible_options_group(parser, defaults): group = optparse.OptionGroup(parser, 'Ansible options', 'Ansible-specific options') group.add_option('--applications-postfix', dest='applications_postfix', default=defaults.get('applications_postfix'), help='postfix to append to applications to '\ 'turn them into groups') parser.add_option_group(group) options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, inventory_shortopt='-l', inventory_longopt='--list', inventory_help='output the inventory', nodeinfo_shortopt='-t', nodeinfo_longopt='--host', nodeinfo_dest='hostname', nodeinfo_help='output host_vars for the given host', add_options_cb=add_ansible_options_group, defaults=defaults) class_mappings = defaults.get('class_mappings') if options.mode == MODE_NODEINFO: data = get_nodeinfo(options.storage_type, options.inventory_base_uri, options.nodes_uri, options.classes_uri, options.file_extension, options.hostname, class_mappings) # Massage and shift the data like Ansible wants it data['parameters']['__reclass__'] = data['__reclass__'] for i in ('classes', 'applications'): data['parameters']['__reclass__'][i] = data[i] data = data['parameters'] else: data = get_inventory(options.storage_type, options.inventory_base_uri, options.nodes_uri, options.classes_uri, options.file_extension, class_mappings) # Ansible inventory is only the list of groups. Groups are the set # of classes plus the set of applications with the postfix added: groups = data['classes'] apps = data['applications'] if options.applications_postfix: postfix = options.applications_postfix groups.update([(k + postfix, v) for k,v in apps.iteritems()]) else: groups.update(apps) data = groups print output(data, options.output, options.pretty_print) except ReclassException, e: e.exit_with_message(sys.stderr)
def config(self): return find_and_read_configfile()
def _deps(ret_classes=True, ret_errors=False): ''' Returns classes if ret_classes=True, else returns soft_params if ret_classes=False ''' defaults = find_and_read_configfile() path = defaults.get('inventory_base_uri') classes = {} soft_params = {} errors = [] # find classes for root, dirs, files in os.walk(path): # skip hidden files and folders in reclass dir files = [f for f in files if not f[0] == '.'] dirs[:] = [d for d in dirs if not d[0] == '.'] # translate found init.yml to valid class name if 'init.yml' in files: class_file = root + '/' + 'init.yml' class_name = class_file.replace(path, '')[:-9].replace('/', '.') classes[class_name] = {'file': class_file} for f in files: if f.endswith('.yml') and f != 'init.yml': class_file = root + '/' + f class_name = class_file.replace(path, '')[:-4].replace('/', '.') classes[class_name] = {'file': class_file} # read classes for class_name, params in classes.items(): LOG.debug("Processing:{}".format(params['file'])) with open(params['file'], 'r') as f: # read raw data raw = f.read() pr = re.findall('\${_param:(.*?)}', raw) if pr: params['params_required'] = list(set(pr)) # load yaml try: data = yaml.load(raw) except yaml.scanner.ScannerError as e: errors.append(params['file'] + ' ' + str(e)) pass if type(data) == dict: if data.get('classes'): params['includes'] = data.get('classes', []) if data.get('parameters') and data['parameters'].get('_param'): params['params_created'] = data['parameters']['_param'] if not (data.get('classes') or data.get('parameters')): errors.append(params['file'] + ' ' + 'file missing classes and parameters') else: errors.append(params['file'] + ' ' + 'is not valid yaml') if ret_classes: return classes elif ret_errors: return errors # find parameters and its usage for class_name, params in classes.items(): for pn, pv in params.get('params_created', {}).items(): # create param if missing if pn not in soft_params: soft_params[pn] = {'created_at': {}, 'required_at': []} # add created_at if class_name not in soft_params[pn]['created_at']: soft_params[pn]['created_at'][class_name] = pv for pn in params.get('params_required', []): # create param if missing if pn not in soft_params: soft_params[pn] = {'created_at': {}, 'required_at': []} # add created_at soft_params[pn]['required_at'].append(class_name) return soft_params