Esempio n. 1
0
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)
Esempio n. 2
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. 3
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. 4
0
    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
Esempio n. 5
0
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)
Esempio n. 6
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)
        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)
Esempio n. 7
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)
Esempio n. 8
0
def _get_classes_dir():
    defaults = find_and_read_configfile()
    return os.path.join(defaults.get('inventory_base_uri'), 'classes')
Esempio n. 9
0
def _get_nodes_dir():
    defaults = find_and_read_configfile()
    return defaults.get('nodes_uri') or \
        os.path.join(defaults.get('inventory_base_uri'), 'nodes')
Esempio n. 10
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)
Esempio n. 11
0
def _get_classes_dir():
    defaults = find_and_read_configfile()
    return os.path.join(defaults.get('inventory_base_uri'), 'classes')
Esempio n. 12
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, 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)
Esempio n. 13
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',
                    '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)
Esempio n. 14
0
 def config(self):
     return find_and_read_configfile()
Esempio n. 15
0
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