Fixes #4485 add an ipv6 parameter to accelerate so that the daemon will bind to an ipv6 port instead of ipv4

This commit is contained in:
James Tanner 2013-11-04 17:20:03 -05:00
parent 5c34ed0827
commit c1ed47933b
5 changed files with 32 additions and 8 deletions

View file

@ -315,6 +315,7 @@ class PlayBook(object):
transport=task.transport, sudo_pass=task.sudo_pass, is_playbook=True,
check=self.check, diff=self.diff, environment=task.environment, complex_args=task.args,
accelerate=task.play.accelerate, accelerate_port=task.play.accelerate_port,
accelerate_ipv6=task.play.accelerate_ipv6,
error_on_undefined_vars=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR
)
@ -456,6 +457,7 @@ class PlayBook(object):
transport=play.transport, sudo_pass=self.sudo_pass, is_playbook=True, module_vars=play.vars,
default_vars=play.default_vars, check=self.check, diff=self.diff,
accelerate=play.accelerate, accelerate_port=play.accelerate_port,
accelerate_ipv6=accelerate_ipv6,
).run()
self.stats.compute(setup_results, setup=True)

View file

@ -32,7 +32,7 @@ class Play(object):
__slots__ = [
'hosts', 'name', 'vars', 'default_vars', 'vars_prompt', 'vars_files',
'handlers', 'remote_user', 'remote_port', 'included_roles', 'accelerate',
'accelerate_port', 'sudo', 'sudo_user', 'transport', 'playbook',
'accelerate_port', 'accelerate_ipv6', 'sudo', 'sudo_user', 'transport', 'playbook',
'tags', 'gather_facts', 'serial', '_ds', '_handlers', '_tasks',
'basedir', 'any_errors_fatal', 'roles', 'max_fail_pct'
]
@ -41,7 +41,7 @@ class Play(object):
# and don't line up 1:1 with how they are stored
VALID_KEYS = [
'hosts', 'name', 'vars', 'vars_prompt', 'vars_files',
'tasks', 'handlers', 'remote_user', 'user', 'port', 'include', 'accelerate', 'accelerate_port',
'tasks', 'handlers', 'remote_user', 'user', 'port', 'include', 'accelerate', 'accelerate_port', 'accelerate_ipv6',
'sudo', 'sudo_user', 'connection', 'tags', 'gather_facts', 'serial',
'any_errors_fatal', 'roles', 'pre_tasks', 'post_tasks', 'max_fail_percentage'
]
@ -104,7 +104,6 @@ class Play(object):
raise errors.AnsibleError('hosts declaration is required')
elif isinstance(hosts, list):
hosts = ';'.join(hosts)
self.serial = int(ds.get('serial', 0))
self.hosts = hosts
self.name = ds.get('name', self.hosts)
@ -120,6 +119,7 @@ class Play(object):
self.any_errors_fatal = utils.boolean(ds.get('any_errors_fatal', 'false'))
self.accelerate = utils.boolean(ds.get('accelerate', 'false'))
self.accelerate_port = ds.get('accelerate_port', None)
self.accelerate_ipv6 = ds.get('accelerate_ipv6', False)
self.max_fail_pct = int(ds.get('max_fail_percentage', 100))
load_vars = {}

View file

@ -138,6 +138,7 @@ class Runner(object):
complex_args=None, # structured data in addition to module_args, must be a dict
error_on_undefined_vars=C.DEFAULT_UNDEFINED_VAR_BEHAVIOR, # ex. False
accelerate=False, # use accelerated connection
accelerate_ipv6=False, # accelerated connection w/ IPv6
accelerate_port=None, # port to use with accelerated connection
):
@ -183,6 +184,7 @@ class Runner(object):
self.error_on_undefined_vars = error_on_undefined_vars
self.accelerate = accelerate
self.accelerate_port = accelerate_port
self.accelerate_ipv6 = accelerate_ipv6
self.callbacks.runner = self
self.original_transport = self.transport

View file

@ -84,7 +84,7 @@ class Connection(object):
utils.AES_KEYS = self.runner.aes_keys
def _execute_accelerate_module(self):
args = "password=%s port=%s debug=%d" % (base64.b64encode(self.key.__str__()), str(self.accport), int(utils.VERBOSITY))
args = "password=%s port=%s debug=%d ipv6=%s" % (base64.b64encode(self.key.__str__()), str(self.accport), int(utils.VERBOSITY), self.runner.accelerate_ipv6)
inject = dict(password=self.key)
if self.runner.accelerate_inventory_host:
inject = utils.combine_vars(inject, self.runner.inventory.get_variables(self.runner.accelerate_inventory_host))

View file

@ -47,6 +47,12 @@ options:
this number of minutes before turning itself off.
required: false
default: 30
ipv6:
description:
- The listener daemon on the remote host will bind to the ipv6 localhost socket
if this parameter is set to true.
required: false
default: false
notes:
- See the advanced playbooks chapter for more about using accelerated mode.
requirements: [ "python-keyczar" ]
@ -137,7 +143,7 @@ def daemonize_self(module, password, port, minutes):
if pid > 0:
vvv("exiting pid %s" % pid)
# exit first parent
module.exit_json(msg="daemonized accelerate on port %s for %s minutes" % (port, minutes))
module.exit_json(msg="daemonized accelerate on port %s for %s minutes with pid %s" % (port, minutes, str(pid)))
except OSError, e:
log("fork #1 failed: %d (%s)" % (e.errno, e.strerror))
sys.exit(1)
@ -190,6 +196,15 @@ class ThreadedTCPServer(SocketServer.ThreadingTCPServer):
self.timeout = timeout
SocketServer.ThreadingTCPServer.__init__(self, server_address, RequestHandlerClass)
class ThreadedTCPV6Server(SocketServer.ThreadingTCPServer):
def __init__(self, server_address, RequestHandlerClass, module, password, timeout):
self.module = module
self.address_family = socket.AF_INET6
self.key = AesKey.Read(password)
self.allow_reuse_address = True
self.timeout = timeout
SocketServer.ThreadingTCPServer.__init__(self, server_address, RequestHandlerClass)
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def send_data(self, data):
packed_len = struct.pack('!Q', len(data))
@ -385,7 +400,7 @@ class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
self.server.module.atomic_move(out_path, final_path)
return dict()
def daemonize(module, password, port, timeout, minutes):
def daemonize(module, password, port, timeout, minutes, ipv6):
try:
daemonize_self(module, password, port, minutes)
@ -395,7 +410,10 @@ def daemonize(module, password, port, timeout, minutes):
signal.signal(signal.SIGALRM, catcher)
signal.setitimer(signal.ITIMER_REAL, 60 * minutes)
server = ThreadedTCPServer(("0.0.0.0", port), ThreadedTCPRequestHandler, module, password, timeout)
if ipv6:
server = ThreadedTCPV6Server(("::", port), ThreadedTCPRequestHandler, module, password, timeout)
else:
server = ThreadedTCPServer(("0.0.0.0", port), ThreadedTCPRequestHandler, module, password, timeout)
server.allow_reuse_address = True
vv("serving!")
@ -410,6 +428,7 @@ def main():
module = AnsibleModule(
argument_spec = dict(
port=dict(required=False, default=5099),
ipv6=dict(required=False, default=False),
timeout=dict(required=False, default=300),
password=dict(required=True),
minutes=dict(required=False, default=30),
@ -423,13 +442,14 @@ def main():
timeout = int(module.params['timeout'])
minutes = int(module.params['minutes'])
debug = int(module.params['debug'])
ipv6 = bool(module.params['ipv6'])
if not HAS_KEYCZAR:
module.fail_json(msg="keyczar is not installed (on the remote side)")
DEBUG_LEVEL=debug
daemonize(module, password, port, timeout, minutes)
daemonize(module, password, port, timeout, minutes, ipv6)
# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>