Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
 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)
Esempio n. 7
0
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
Esempio n. 8
0
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)
Esempio n. 9
0
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)
Esempio n. 10
0
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
Esempio n. 11
0
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)
Esempio n. 12
0
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
Esempio n. 13
0
    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)
Esempio n. 14
0
 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]
Esempio n. 15
0
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)
Esempio n. 16
0
 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]
Esempio n. 17
0
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
Esempio n. 18
0
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
Esempio n. 19
0
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)
Esempio n. 20
0
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)