From c612129d64ac98e0dfee30318bf3105e866c6452 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Wed, 5 Oct 2022 08:31:37 -0400 Subject: [PATCH] Have syncfiles attempt to use client ip, if feasible When a node installs, it may not have it's node mapped address up, or may not have one at all. Try to use the ip if it would be in the same set that produced it's ssh certificate. There remains a gap if a system has no static addressing *and* doesn't map nodename to IP, but we have an impasse as the situation is too fuzzy to grant a prinicpal in an SSH cert, and without that we can't securely attempt rsync. For now, this scenario would still fail and I will just hope that doesn't come up. --- confluent_server/bin/confluent_selfcheck | 1 + confluent_server/confluent/selfservice.py | 6 +++++- confluent_server/confluent/syncfiles.py | 11 +++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/confluent_server/bin/confluent_selfcheck b/confluent_server/bin/confluent_selfcheck index 72a1857b..e22d47b1 100755 --- a/confluent_server/bin/confluent_selfcheck +++ b/confluent_server/bin/confluent_selfcheck @@ -281,3 +281,4 @@ if __name__ == '__main__': # possible checks: # arping on the node, check for dupes/against nodeinventory? # arping -D for mgt own ip addresses? check for dupes, also check for bleed through from one nic to another +# iterate through profiles, use mtools to extract site initramfs, check if outdated diff --git a/confluent_server/confluent/selfservice.py b/confluent_server/confluent/selfservice.py index 3a48db75..2f17d456 100644 --- a/confluent_server/confluent/selfservice.py +++ b/confluent_server/confluent/selfservice.py @@ -70,6 +70,7 @@ def handle_request(env, start_response): configmanager.check_quorum() cfg = configmanager.ConfigManager(None) nodename = env.get('HTTP_CONFLUENT_NODENAME', None) + clientip = env.get('HTTP_X_FORWARDED_FOR', None) if env['PATH_INFO'] == '/self/registerapikey': crypthmac = env.get('HTTP_CONFLUENT_CRYPTHMAC', None) if int(env.get('CONTENT_LENGTH', 65)) > 64: @@ -459,8 +460,11 @@ def handle_request(env, start_response): return elif env['PATH_INFO'].startswith('/self/remotesyncfiles'): if 'POST' == operation: + pals = get_extra_names(nodename, cfg, myip) + if clientip not in pals: + clientip = None result = syncfiles.start_syncfiles( - nodename, cfg, json.loads(reqbody)) + nodename, cfg, json.loads(reqbody), clientip) start_response(result, ()) yield '' return diff --git a/confluent_server/confluent/syncfiles.py b/confluent_server/confluent/syncfiles.py index b6598edd..a64b3c98 100644 --- a/confluent_server/confluent/syncfiles.py +++ b/confluent_server/confluent/syncfiles.py @@ -162,7 +162,7 @@ class SyncList(object): self.optmap[f] = entopts -def sync_list_to_node(sl, node, suffixes): +def sync_list_to_node(sl, node, suffixes, peerip=None): targdir = tempfile.mkdtemp('.syncto{}'.format(node)) output = '' try: @@ -187,8 +187,11 @@ def sync_list_to_node(sl, node, suffixes): stage_ent(sl.appendoncemap, ent, os.path.join(targdir, suffixes['appendonce']), True) sshutil.prep_ssh_key('/etc/confluent/ssh/automation') + targip = node + if peerip: + targip = peerip output = util.run( - ['rsync', '-rvLD', targdir + '/', 'root@{}:/'.format(node)])[0] + ['rsync', '-rvLD', targdir + '/', 'root@{}:/'.format(targip)])[0] except Exception as e: if 'CalledProcessError' not in repr(e): # https://github.com/eventlet/eventlet/issues/413 @@ -275,7 +278,7 @@ def mkpathorlink(source, destination, appendexist=False): syncrunners = {} -def start_syncfiles(nodename, cfg, suffixes): +def start_syncfiles(nodename, cfg, suffixes, peerip=None): deployinfo = cfg.get_node_attributes( nodename, ('deployment.*',)) deployinfo = deployinfo.get(nodename, {}) @@ -296,7 +299,7 @@ def start_syncfiles(nodename, cfg, suffixes): if not (sl.appendmap or sl.mergemap or sl.replacemap or sl.appendoncemap): return '200 OK' # the synclist has no actual entries syncrunners[nodename] = eventlet.spawn( - sync_list_to_node, sl, nodename, suffixes) + sync_list_to_node, sl, nodename, suffixes, peerip) return '202 Queued' # backgrounded def get_syncresult(nodename):