From 18863078458f7f2cbf58f2d6206a4e663c716358 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Tue, 19 Aug 2014 11:55:29 -0400 Subject: [PATCH] Fix a parsing bug that prevents IPv6 addresses from being used with `add_host` Closes #8682 --- lib/ansible/plugins/action/add_host.py | 28 ++++++++++++- test/units/plugins/action/test_add_host.py | 47 ++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 test/units/plugins/action/test_add_host.py diff --git a/lib/ansible/plugins/action/add_host.py b/lib/ansible/plugins/action/add_host.py index 12c9febe95..3d38024600 100644 --- a/lib/ansible/plugins/action/add_host.py +++ b/lib/ansible/plugins/action/add_host.py @@ -20,6 +20,8 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type +import re + from ansible.plugins.action import ActionBase class ActionModule(ActionBase): @@ -38,8 +40,8 @@ class ActionModule(ActionBase): new_name = self._task.args.get('name', self._task.args.get('hostname', None)) #vv("creating host via 'add_host': hostname=%s" % new_name) - if ":" in new_name: - new_name, new_port = new_name.split(":") + new_name, new_port = _parse_ip_host_and_port(new_name) + if new_port: self._task.args['ansible_ssh_port'] = new_port groups = self._task.args.get('groupname', self._task.args.get('groups', self._task.args.get('group', ''))) @@ -58,4 +60,26 @@ class ActionModule(ActionBase): return dict(changed=True, add_host=dict(host_name=new_name, groups=new_groups, host_vars=host_vars)) +def _parse_ip_host_and_port(hostname): + """ + Attempt to parse the hostname and port from a hostname, e.g., + some-host-name + some-host-name:80 + 8.8.8.8 + 8.8.8.8:80 + 2001:db8:0:1 + [2001:db8:0:1]:80 + """ + if hostname.count(':') > 1: + match = re.match( + '\[(?P[^\]]+)\](:(?P[0-9]+))?', + hostname + ) + if match: + return match.group('ip'), match.group('port') + else: + return hostname, None + elif ':' in hostname: + return hostname.split(':') + return hostname, None diff --git a/test/units/plugins/action/test_add_host.py b/test/units/plugins/action/test_add_host.py new file mode 100644 index 0000000000..c694d387a3 --- /dev/null +++ b/test/units/plugins/action/test_add_host.py @@ -0,0 +1,47 @@ +import unittest + +from ansible.plugins.action import add_host + + +class TestAddHost(unittest.TestCase): + + def test_hostname(self): + host, port = add_host._parse_ip_host_and_port('some-remote-host') + assert host == 'some-remote-host' + assert port is None + + def test_hostname_with_port(self): + host, port = add_host._parse_ip_host_and_port('some-remote-host:80') + assert host == 'some-remote-host' + assert port == '80' + + def test_parse_ip_host_and_port_v4(self): + host, port = add_host._parse_ip_host_and_port('8.8.8.8') + assert host == '8.8.8.8' + assert port is None + + def test_parse_ip_host_and_port_v4_and_port(self): + host, port = add_host._parse_ip_host_and_port('8.8.8.8:80') + assert host == '8.8.8.8' + assert port == '80' + + def test_parse_ip_host_and_port_v6(self): + host, port = add_host._parse_ip_host_and_port( + 'dead:beef:dead:beef:dead:beef:dead:beef' + ) + assert host == 'dead:beef:dead:beef:dead:beef:dead:beef' + assert port is None + + def test_parse_ip_host_and_port_v6_with_brackets(self): + host, port = add_host._parse_ip_host_and_port( + '[dead:beef:dead:beef:dead:beef:dead:beef]' + ) + assert host == 'dead:beef:dead:beef:dead:beef:dead:beef' + assert port is None + + def test_parse_ip_host_and_port_v6_with_brackets_and_port(self): + host, port = add_host._parse_ip_host_and_port( + '[dead:beef:dead:beef:dead:beef:dead:beef]:80' + ) + assert host == 'dead:beef:dead:beef:dead:beef:dead:beef' + assert port == '80'