def top(minion_id, storage_type=OPT_STORAGE_TYPE, inventory_base_uri=OPT_INVENTORY_BASE_URI, nodes_uri=OPT_NODES_URI, classes_uri=OPT_CLASSES_URI, class_mappings=None): nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri) storage = get_storage(storage_type, nodes_uri, classes_uri, default_environment='base') reclass = Core(storage, class_mappings) # if the minion_id is not None, then return just the applications for the # specific minion, otherwise return the entire top data (which we need for # CLI invocations of the adapter): if minion_id is not None: data = reclass.nodeinfo(minion_id) applications = data.get('applications', []) env = data['environment'] return {env: applications} else: data = reclass.inventory() nodes = {} for node_id, node_data in data['nodes'].iteritems(): env = node_data['environment'] if env not in nodes: nodes[env] = {} nodes[env][node_id] = node_data['applications'] return nodes
def ext_pillar(minion_id, pillar, storage_type=OPT_STORAGE_TYPE, inventory_base_uri=OPT_INVENTORY_BASE_URI, nodes_uri=OPT_NODES_URI, classes_uri=OPT_CLASSES_URI, class_mappings=None, propagate_pillar_data_to_reclass=False): nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri) storage = get_storage(storage_type, nodes_uri, classes_uri, default_environment='base') input_data = None if propagate_pillar_data_to_reclass: input_data = pillar reclass = Core(storage, class_mappings, input_data=input_data) data = reclass.nodeinfo(minion_id) params = data.get('parameters', {}) params['__reclass__'] = {} params['__reclass__']['nodename'] = minion_id params['__reclass__']['applications'] = data['applications'] params['__reclass__']['classes'] = data['classes'] params['__reclass__']['environment'] = data['environment'] return params
def top(minion_id, storage_type=OPT_STORAGE_TYPE, inventory_base_uri=OPT_INVENTORY_BASE_URI, nodes_uri=OPT_NODES_URI, classes_uri=OPT_CLASSES_URI, class_mappings=None, compose_node_name=OPT_COMPOSE_NODE_NAME, **kwargs): path_mangler = get_path_mangler(storage_type) nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri) storage = get_storage(storage_type, nodes_uri, classes_uri, compose_node_name) settings = Settings(kwargs) reclass = Core(storage, class_mappings, settings, input_data=None) # if the minion_id is not None, then return just the applications for the # specific minion, otherwise return the entire top data (which we need for # CLI invocations of the adapter): if minion_id is not None: data = reclass.nodeinfo(minion_id) applications = data.get('applications', []) env = data['environment'] return {env: applications} else: data = reclass.inventory() nodes = {} for (node_id, node_data) in iteritems(data['nodes']): env = node_data['environment'] if env not in nodes: nodes[env] = {} nodes[env][node_id] = node_data['applications'] return nodes
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 ext_pillar(minion_id, pillar, storage_type=OPT_STORAGE_TYPE, inventory_base_uri=OPT_INVENTORY_BASE_URI, nodes_uri=OPT_NODES_URI, classes_uri=OPT_CLASSES_URI, class_mappings=None, propagate_pillar_data_to_reclass=False, **kwargs): path_mangler = get_path_mangler(storage_type) nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri) storage = get_storage(storage_type, nodes_uri, classes_uri) input_data = None if propagate_pillar_data_to_reclass: input_data = pillar settings = Settings(kwargs) reclass = Core(storage, class_mappings, settings, input_data=input_data) data = reclass.nodeinfo(minion_id) params = data.get('parameters', {}) params['__reclass__'] = {} params['__reclass__']['nodename'] = minion_id params['__reclass__']['applications'] = data['applications'] params['__reclass__']['classes'] = data['classes'] params['__reclass__']['environment'] = data['environment'] return params
def _core(self, dataset, opts={}): inventory_uri = os.path.dirname(os.path.abspath(__file__)) + '/data/' + dataset path_mangler = get_path_mangler('yaml_fs') nodes_uri, classes_uri = path_mangler(inventory_uri, 'nodes', 'classes') settings = Settings(opts) storage = get_storage('yaml_fs', nodes_uri, classes_uri, settings.compose_node_name) return Core(storage, None, settings)
def inventory_reclass(inventory_path, ignore_class_notfound=False): """ Runs a reclass inventory in inventory_path (same output as running ./reclass.py -b inv_base_uri/ --inventory) Will attempt to read reclass config from 'reclass-config.yml' otherwise it will failback to the default config. Returns a reclass style dictionary Does not throw errors if a class is not found while --fetch flag is enabled """ if not cached.inv: reclass_config = { "storage_type": "yaml_fs", "inventory_base_uri": inventory_path, "nodes_uri": os.path.join(inventory_path, "targets"), "classes_uri": os.path.join(inventory_path, "classes"), "compose_node_name": False, "allow_none_override": True, "ignore_class_notfound": ignore_class_notfound, } try: cfg_file = os.path.join(inventory_path, "reclass-config.yml") with open(cfg_file) as reclass_cfg: reclass_config = yaml.load(reclass_cfg, Loader=YamlLoader) # normalise relative nodes_uri and classes_uri paths for uri in ("nodes_uri", "classes_uri"): uri_val = reclass_config.get(uri) uri_path = os.path.join(inventory_path, uri_val) normalised_path = os.path.normpath(uri_path) reclass_config.update({uri: normalised_path}) logger.debug("Using reclass inventory config at: %s", cfg_file) except IOError as ex: # If file does not exist, ignore if ex.errno == errno.ENOENT: logger.debug("Using reclass inventory config defaults") try: storage = reclass.get_storage( reclass_config["storage_type"], reclass_config["nodes_uri"], reclass_config["classes_uri"], reclass_config["compose_node_name"], ) class_mappings = reclass_config.get( "class_mappings") # this defaults to None (disabled) _reclass = reclass.core.Core( storage, class_mappings, reclass.settings.Settings(reclass_config)) cached.inv = _reclass.inventory() except ReclassException as e: if isinstance(e, NotFoundError): logger.error("Inventory reclass error: inventory not found") else: logger.error("Inventory reclass error: %s", e.message) raise InventoryError(e.message) return cached.inv
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 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. 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 main(): try: defaults = { 'no_refs': OPT_NO_REFS, '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) 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.nodename) else: data = reclass.inventory() 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 inventory_reclass(inventory_path): """ Runs a reclass inventory in inventory_path (same output as running ./reclass.py -b inv_base_uri/ --inventory) Will attempt to read reclass config from 'reclass-config.yml' otherwise it will failback to the default config. Returns a reclass style dictionary """ if not cached.inv: reclass_config = { 'storage_type': 'yaml_fs', 'inventory_base_uri': inventory_path, 'nodes_uri': os.path.join(inventory_path, 'targets'), 'classes_uri': os.path.join(inventory_path, 'classes'), 'compose_node_name': False } try: cfg_file = os.path.join(inventory_path, 'reclass-config.yml') with open(cfg_file) as reclass_cfg: reclass_config = yaml.load(reclass_cfg, Loader=YamlLoader) # normalise relative nodes_uri and classes_uri paths for uri in ('nodes_uri', 'classes_uri'): uri_val = reclass_config.get(uri) uri_path = os.path.join(inventory_path, uri_val) normalised_path = os.path.normpath(uri_path) reclass_config.update({uri: normalised_path}) logger.debug("Using reclass inventory config at: %s", cfg_file) except IOError as ex: # If file does not exist, ignore if ex.errno == errno.ENOENT: logger.debug("Using reclass inventory config defaults") try: storage = reclass.get_storage(reclass_config['storage_type'], reclass_config['nodes_uri'], reclass_config['classes_uri'], reclass_config['compose_node_name']) class_mappings = reclass_config.get( 'class_mappings') # this defaults to None (disabled) _reclass = reclass.core.Core( storage, class_mappings, reclass.settings.Settings(reclass_config)) cached.inv = _reclass.inventory() except ReclassException as e: if isinstance(e, NotFoundError): logger.error("Inventory reclass error: inventory not found") else: logger.error("Inventory reclass error: %s", e.message) raise InventoryError(e.message) return cached.inv
def __init__(self, nodes_uri, classes_uri): super(ExternalNodeStorage, self).__init__(STORAGE_NAME) self._nodes_uri = self._uri(nodes_uri) self._nodes_storage = get_storage(self._nodes_uri.storage_type, self._nodes_uri.options, None) self._classes_default_uri = self._uri(classes_uri) self._classes_default_storage = get_storage( self._classes_default_uri.storage_type, None, self._classes_default_uri.options) self._classes_storage = dict() if 'env_overrides' in classes_uri: for override in classes_uri['env_overrides']: for (env, options) in iteritems(override): uri = copy.deepcopy(classes_uri) uri.update(options) uri = self._uri(uri) self._classes_storage[env] = get_storage( uri.storage_type, None, uri.options)
def inventory(self, resource=None): ''' Get inventory nodes from reclass salt formals and their associated services and roles. ''' storage = get_storage('yaml_fs', self.metadata['node_dir'], self.metadata['class_dir']) reclass = Core(storage, None) if resource is None: return reclass.inventory()["nodes"] else: return reclass.inventory()["nodes"][resource]
def get_core(key=None): """Initializes reclass Core() using /etc/reclass settings""" defaults = reclass_config.find_and_read_configfile() inventory_base_uri = defaults['inventory_base_uri'] storage_type = defaults['storage_type'] nodes_uri, classes_uri = reclass_config.path_mangler( inventory_base_uri, None, None) storage = reclass.get_storage(storage_type, nodes_uri, classes_uri, default_environment='base') #key = '_param.keepalived_vip_interface' return ReclassCore(storage, None, None, key=key)
def inventory(self, resource=None): ''' Get inventory nodes from reclass and their associated services and roles. ''' storage = get_storage(self.metadata['storage_type'], self.metadata['node_dir'], self.metadata['class_dir']) settings = Settings({ 'no_refs': False, 'pretty_print': True, 'output': 'yaml' }) reclass = Core(storage, None, settings) if resource is None: return reclass.inventory()["nodes"] else: return reclass.inventory()["nodes"][resource]
def inventory_reclass(inventory_path): """ Runs a reclass inventory in inventory_path (same output as running ./reclass.py -b streams/ --inventory) Will attempt to read reclass config from 'reclass-config.yml' otherwise it will failback to the default config. Returns a reclass style dictionary """ reclass_config = { 'storage_type': 'yaml_fs', 'inventory_base_uri': inventory_path, 'nodes_uri': os.path.join(inventory_path, 'targets'), 'classes_uri': os.path.join(inventory_path, 'classes') } try: cfg_file = os.path.join(inventory_path, 'reclass-config.yml') with open(cfg_file) as reclass_cfg: reclass_config = yaml.safe_load(reclass_cfg) # normalise relative nodes_uri and classes_uri paths for uri in ('nodes_uri', 'classes_uri'): uri_val = reclass_config.get(uri) uri_path = os.path.join(inventory_path, uri_val) normalised_path = os.path.normpath(uri_path) reclass_config.update({uri: normalised_path}) logger.debug("Using reclass inventory config at: %s", cfg_file) except IOError as ex: # If file does not exist, ignore if ex.errno == errno.ENOENT: logger.debug("Using reclass inventory config defaults") storage = reclass.get_storage(reclass_config['storage_type'], reclass_config['nodes_uri'], reclass_config['classes_uri'], default_environment='base') class_mappings = reclass_config.get( 'class_mappings') # this defaults to None (disabled) _reclass = reclass.core.Core(storage, class_mappings) inv = _reclass.inventory() logger.debug("reclass inventory: %s", inv) return inv
def ext_pillar(minion_id, pillar, storage_type=OPT_STORAGE_TYPE, inventory_base_uri=OPT_INVENTORY_BASE_URI, nodes_uri=OPT_NODES_URI, classes_uri=OPT_CLASSES_URI, class_mappings=None): nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri) storage = get_storage(storage_type, nodes_uri, classes_uri, default_environment='base') reclass = Core(storage, class_mappings) data = reclass.nodeinfo(minion_id) params = data.get('parameters', {}) params['__reclass__'] = {} params['__reclass__']['applications'] = data['applications'] params['__reclass__']['classes'] = data['classes'] params['__reclass__']['environment'] = data['environment'] return params
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) 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 apps.iteritems()]) else: groups.update(apps) data = groups print output(data, options.output, options.pretty_print, options.no_refs) 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)