Esempio n. 1
0
    def test_with_ranges(self):
        for t in self.range_tests:
            test = self.range_tests[t]

            try:
                (host, port) = parse_address(t, allow_ranges=True)
            except Exception:
                host = None
                port = None

            assert host == test[0]
            assert port == test[1]
Esempio n. 2
0
    def test_without_ranges(self):
        for t in self.tests:
            test = self.tests[t]

            try:
                (host, port) = parse_address(t)
            except Exception:
                host = None
                port = None

            assert host == test[0]
            assert port == test[1]
Esempio n. 3
0
def split_host_pattern(pattern):
    """
    Takes a string containing host patterns separated by commas (or a list
    thereof) and returns a list of single patterns (which may not contain
    commas). Whitespace is ignored.

    Also accepts ':' as a separator for backwards compatibility, but it is
    not recommended due to the conflict with IPv6 addresses and host ranges.

    Example: 'a,b[1], c[2:3] , d' -> ['a', 'b[1]', 'c[2:3]', 'd']
    """

    if isinstance(pattern, list):
        results = (split_host_pattern(p) for p in pattern)
        # flatten the results
        return list(itertools.chain.from_iterable(results))
    elif not isinstance(pattern, string_types):
        pattern = to_text(pattern, errors='surrogate_or_strict')

    # If it's got commas in it, we'll treat it as a straightforward
    # comma-separated list of patterns.
    if u',' in pattern:
        patterns = pattern.split(u',')

    # If it doesn't, it could still be a single pattern. This accounts for
    # non-separator uses of colons: IPv6 addresses and [x:y] host ranges.
    else:
        try:
            (base, port) = parse_address(pattern, allow_ranges=True)
            patterns = [pattern]
        except Exception:
            # The only other case we accept is a ':'-separated list of patterns.
            # This mishandles IPv6 addresses, and is retained only for backwards
            # compatibility.
            patterns = re.findall(
                to_text(r'''(?:     # We want to match something comprising:
                        [^\s:\[\]]  # (anything other than whitespace or ':[]'
                        |           # ...or...
                        \[[^\]]*\]  # a single complete bracketed expression)
                    )+              # occurring once or more
                '''), pattern, re.X)

    return [p.strip() for p in patterns if p.strip()]
Esempio n. 4
0
    def parse(self, inventory, loader, host_list, cache=True):
        ''' parses the inventory file '''

        super(InventoryModule, self).parse(inventory, loader, host_list)

        try:
            for h in host_list.split(','):
                h = h.strip()
                if h:
                    try:
                        (host, port) = parse_address(h, allow_ranges=False)
                    except AssibleError as e:
                        self.display.vvv("Unable to parse address from hostname, leaving unchanged: %s" % to_text(e))
                        host = h
                        port = None

                    if host not in self.inventory.hosts:
                        self.inventory.add_host(host, group='ungrouped', port=port)
        except Exception as e:
            raise AssibleParserError("Invalid data from string, could not parse: %s" % to_native(e))
Esempio n. 5
0
    def _expand_hostpattern(self, hostpattern):
        '''
        Takes a single host pattern and returns a list of hostnames and an
        optional port number that applies to all of them.
        '''
        # Can the given hostpattern be parsed as a host with an optional port
        # specification?

        try:
            (pattern, port) = parse_address(hostpattern, allow_ranges=True)
        except Exception:
            # not a recognizable host pattern
            pattern = hostpattern
            port = None

        # Once we have separated the pattern, we expand it into list of one or
        # more hostnames, depending on whether it contains any [x:y] ranges.

        if detect_range(pattern):
            hostnames = expand_hostname_range(pattern)
        else:
            hostnames = [pattern]

        return (hostnames, port)
Esempio n. 6
0
    def run(self, tmp=None, task_vars=None):

        self._supports_check_mode = True

        result = super(ActionModule, self).run(tmp, task_vars)
        del tmp  # tmp no longer has any effect

        args = self._task.args
        raw = args.pop('_raw_params', {})
        if isinstance(raw, Mapping):
            # TODO: create 'conflict' detection in base class to deal with repeats and aliases and warn user
            args = combine_vars(raw, args)
        else:
            raise AssibleActionFail(
                'Invalid raw parameters passed, requires a dictonary/mapping got a  %s'
                % type(raw))

        # Parse out any hostname:port patterns
        new_name = args.get('name', args.get('hostname',
                                             args.get('host', None)))
        if new_name is None:
            raise AssibleActionFail(
                'name, host or hostname needs to be provided')

        display.vv("creating host via 'add_host': hostname=%s" % new_name)

        try:
            name, port = parse_address(new_name, allow_ranges=False)
        except Exception:
            # not a parsable hostname, but might still be usable
            name = new_name
            port = None

        if port:
            args['assible_ssh_port'] = port

        groups = args.get('groupname', args.get('groups',
                                                args.get('group', '')))
        # add it to the group if that was specified
        new_groups = []
        if groups:
            if isinstance(groups, list):
                group_list = groups
            elif isinstance(groups, string_types):
                group_list = groups.split(",")
            else:
                raise AssibleActionFail("Groups must be specified as a list.",
                                        obj=self._task)

            for group_name in group_list:
                if group_name not in new_groups:
                    new_groups.append(group_name.strip())

        # Add any variables to the new_host
        host_vars = dict()
        special_args = frozenset(('name', 'hostname', 'groupname', 'groups'))
        for k in args.keys():
            if k not in special_args:
                host_vars[k] = args[k]

        result['changed'] = False
        result['add_host'] = dict(host_name=name,
                                  groups=new_groups,
                                  host_vars=host_vars)
        return result
Esempio n. 7
0
    def _populate(self):
        raw_params = dict(
            docker_host=self.get_option('docker_host'),
            tls=self.get_option('tls'),
            tls_verify=self.get_option('validate_certs'),
            key_path=self.get_option('client_key'),
            cacert_path=self.get_option('ca_cert'),
            cert_path=self.get_option('client_cert'),
            tls_hostname=self.get_option('tls_hostname'),
            api_version=self.get_option('api_version'),
            timeout=self.get_option('timeout'),
            ssl_version=self.get_option('ssl_version'),
            debug=None,
        )
        update_tls_hostname(raw_params)
        connect_params = get_connect_params(raw_params,
                                            fail_function=self._fail)
        self.client = docker.DockerClient(**connect_params)
        self.inventory.add_group('all')
        self.inventory.add_group('manager')
        self.inventory.add_group('worker')
        self.inventory.add_group('leader')
        self.inventory.add_group('nonleaders')

        if self.get_option('include_host_uri'):
            if self.get_option('include_host_uri_port'):
                host_uri_port = str(self.get_option('include_host_uri_port'))
            elif self.get_option('tls') or self.get_option('validate_certs'):
                host_uri_port = '2376'
            else:
                host_uri_port = '2375'

        try:
            self.nodes = self.client.nodes.list()
            for self.node in self.nodes:
                self.node_attrs = self.client.nodes.get(self.node.id).attrs
                self.inventory.add_host(self.node_attrs['ID'])
                self.inventory.add_host(self.node_attrs['ID'],
                                        group=self.node_attrs['Spec']['Role'])
                self.inventory.set_variable(self.node_attrs['ID'],
                                            'assible_host',
                                            self.node_attrs['Status']['Addr'])
                if self.get_option('include_host_uri'):
                    self.inventory.set_variable(
                        self.node_attrs['ID'], 'assible_host_uri',
                        'tcp://' + self.node_attrs['Status']['Addr'] + ':' +
                        host_uri_port)
                if self.get_option('verbose_output'):
                    self.inventory.set_variable(
                        self.node_attrs['ID'], 'docker_swarm_node_attributes',
                        self.node_attrs)
                if 'ManagerStatus' in self.node_attrs:
                    if self.node_attrs['ManagerStatus'].get('Leader'):
                        # This is workaround of bug in Docker when in some cases the Leader IP is 0.0.0.0
                        # Check moby/moby#35437 for details
                        swarm_leader_ip = parse_address(self.node_attrs['ManagerStatus']['Addr'])[0] or \
                            self.node_attrs['Status']['Addr']
                        if self.get_option('include_host_uri'):
                            self.inventory.set_variable(
                                self.node_attrs['ID'], 'assible_host_uri',
                                'tcp://' + swarm_leader_ip + ':' +
                                host_uri_port)
                        self.inventory.set_variable(self.node_attrs['ID'],
                                                    'assible_host',
                                                    swarm_leader_ip)
                        self.inventory.add_host(self.node_attrs['ID'],
                                                group='leader')
                    else:
                        self.inventory.add_host(self.node_attrs['ID'],
                                                group='nonleaders')
                else:
                    self.inventory.add_host(self.node_attrs['ID'],
                                            group='nonleaders')
                # Use constructed if applicable
                strict = self.get_option('strict')
                # Composed variables
                self._set_composite_vars(self.get_option('compose'),
                                         self.node_attrs,
                                         self.node_attrs['ID'],
                                         strict=strict)
                # Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
                self._add_host_to_composed_groups(self.get_option('groups'),
                                                  self.node_attrs,
                                                  self.node_attrs['ID'],
                                                  strict=strict)
                # Create groups based on variable values and add the corresponding hosts to it
                self._add_host_to_keyed_groups(self.get_option('keyed_groups'),
                                               self.node_attrs,
                                               self.node_attrs['ID'],
                                               strict=strict)
        except Exception as e:
            raise AssibleError(
                'Unable to fetch hosts from Docker swarm API, this was the original exception: %s'
                % to_native(e))