Modified fn-setup to check FMS, added fn-setupfms command. Features: Modified fn-setup to check the FMS configuration and update the config file. --fmshost, --fmsport, --fmsid set the host, port and fms id respectively. Added fn-setupfms command to test and update the FMS configuration.
diff --git a/infocalypse/__init__.py b/infocalypse/__init__.py --- a/infocalypse/__init__.py +++ b/infocalypse/__init__.py @@ -361,7 +361,8 @@ from infcmds import get_config_info, exe execute_push, execute_setup, execute_copy, execute_reinsert, \ execute_info -from fmscmds import execute_fmsread, execute_fmsnotify, get_uri_from_hash +from fmscmds import execute_fmsread, execute_fmsnotify, get_uri_from_hash, \ + execute_setupfms from sitecmds import execute_putsite, execute_genkey from wikicmds import execute_wiki, execute_wiki_apply @@ -699,6 +700,16 @@ def infocalypse_setup(ui_, **opts): opts['fcpport'], opts['tmpdir']) + if not opts['nofms']: + execute_setupfms(ui_, opts) + else: + ui_.status("Skipped FMS configuration because --nofms was set.\n") + +def infocalypse_setupfms(ui_, **opts): + """ Setup or modify the fms configuration. """ + # REQUIRES config file. + execute_setupfms(ui_, opts) + #----------------------------------------------------------" def do_archive_create(ui_, opts, params, stored_cfg): """ fn-archive --create.""" @@ -795,6 +806,11 @@ FCP_OPTS = [('', 'fcphost', '', 'fcp hos ('', 'fcpport', 0, 'fcp port'), ] +FMS_OPTS = [('', 'fmshost', '', 'fms host'), + ('', 'fmsport', 0, 'fms port'), +] + + AGGRESSIVE_OPT = [('', 'aggressive', None, 'aggressively search for the ' + 'latest USK index'),] NOSEARCH_OPT = [('', 'nosearch', None, 'use USK version in URI'), ] @@ -895,10 +911,19 @@ cmdtable = { "[options]"), "fn-setup": (infocalypse_setup, - [('', 'tmpdir', '~/infocalypse_tmp', 'temp directory'),] - + FCP_OPTS, + [('', 'tmpdir', '~/infocalypse_tmp', 'temp directory'), + ('', 'nofms', None, 'skip FMS configuration'), + ('', 'fmsid', '', "fmsid (only part before '@'!)"), + ('', 'timeout', 30, "fms socket timeout in seconds")] + + FCP_OPTS + + FMS_OPTS, "[options]"), + "fn-setupfms": (infocalypse_setupfms, + [('', 'fmsid', '', "fmsid (only part before '@'!)"), + ('', 'timeout', 30, "fms socket timeout in seconds"),] + + FMS_OPTS, + "[options]"), "fn-archive": (infocalypse_archive, [('', 'uri', '', 'Request URI for --pull, Insert URI ' + @@ -915,10 +940,10 @@ cmdtable = { + NOSEARCH_OPT + AGGRESSIVE_OPT, "[options]"), - } commands.norepo += ' fn-setup' +commands.norepo += ' fn-setupfms' commands.norepo += ' fn-genkey' commands.norepo += ' fn-archive' diff --git a/infocalypse/config.py b/infocalypse/config.py --- a/infocalypse/config.py +++ b/infocalypse/config.py @@ -81,6 +81,7 @@ def norm_path(dir_name): fixed = split[0].replace(':', '') + split[1] return fixed +# REDFLAG: THis is an ancient hack. Safe to back it out? # NOTE: # The bug prevents ConfigParser from even reading # the file. That's why I'm operating on the file @@ -131,7 +132,7 @@ class Config: self.file_name = None # Use a dict instead of members to avoid pylint R0902. - self.defaults = {} + self.defaults = {} # REDFLAG: Why is this called defaults? BAD NAME self.defaults['HOST'] = '127.0.0.1' self.defaults['PORT'] = 9481 self.defaults['TMP_DIR'] = None diff --git a/infocalypse/devnotes.txt b/infocalypse/devnotes.txt --- a/infocalypse/devnotes.txt +++ b/infocalypse/devnotes.txt @@ -1,8 +1,11 @@ !!! experimental branch for testing wiki over hg idea !!! See (note updated uri) -reenet:USK@Gq-FBhpgvr11VGpapG~y0rGFOAHVfzyW1WoKGwK-fFw,MpzFUh5Rmw6N~aMKwm9h2Uk~6aTRhYaY0shXVotgBUc,AQACAAE/fniki/2/ +reenet:USK@Gq-FBhpgvr11VGpapG~y0rGFOAHVfzyW1WoKGwK-fFw,MpzFUh5Rmw6N~aMKwm9h2Uk~6aTRhYaY0shXVotgBUc,AQACAAE/fniki/-22/ !!! +djk20100207 +BUG: fn-wiki will run without .infocalypse. audit other new commands, should abort cleanly. + djk20100123 Saw error reinserting fred staging mirror: {4}:008c3b951f:(102, 117, 0):PutSuccessful diff --git a/infocalypse/fmscmds.py b/infocalypse/fmscmds.py --- a/infocalypse/fmscmds.py +++ b/infocalypse/fmscmds.py @@ -21,6 +21,8 @@ """ # REDFLAG: Go back and fix all the places where you return instead of Abort() +import socket + from mercurial import util from fcpclient import get_usk_hash @@ -416,3 +418,139 @@ def get_uri_from_hash(ui_, dummy, params return target_usk + +CRLF = '\x0d\x0a' +FMS_TIMEOUT_SECS = 30 +FMS_SOCKET_ERR_MSG = """ +Socket level error. +It looks like your FMS host or port might be wrong. +Set them with --fmshost and/or --fmsport. +""" + +def connect_to_fms(ui_, fms_host, fms_port, timeout): + """ INTERNAL: Helper, connects to fms and reads the login msg. """ + ui_.status("Testing FMS connection [%s:%i]...\n" % (fms_host, fms_port)) + try: + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + connected_socket = None + try: + connected_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + connected_socket.connect((fms_host, fms_port)) + bytes = '' + while bytes.find(CRLF) == -1: + bytes = bytes + connected_socket.recv(4096) + finally: + socket.setdefaulttimeout(old_timeout) + if connected_socket: + connected_socket.close() + + except socket.error: # Not an IOError until 2.6. + ui_.warn(FMS_SOCKET_ERR_MSG) + return None + + except IOError: + ui_.warn(FMS_SOCKET_ERR_MSG) + return None + + return bytes + + +# Passing opts instead of separate args to get around pylint +# warning about long arg list. +def get_fms_args(cfg, opts): + """ INTERNAL: Helper to extract args from Config/mercurial opts. """ + def false_to_none(value): + """ INTERNAL: Return None if not bool(value), value otherwise. """ + if value: + return value + return None + + fms_id = false_to_none(opts['fmsid']) + fms_host = false_to_none(opts['fmshost']) + fms_port = false_to_none(opts['fmsport']) + timeout = opts['timeout'] + + if not cfg is None: + if fms_id is None: + fms_id = cfg.defaults.get('FMS_ID', None) + if fms_host is None: + fms_host = cfg.defaults.get('FMS_HOST', None) + if fms_port is None: + fms_port = cfg.defaults.get('FMS_PORT', None) + + if fms_id is None: + fms_id = 'None' # hmmm + if fms_host is None: + fms_host = '127.0.0.1' + if fms_port is None: + fms_port = 1119 + + return (fms_id, fms_host, fms_port, timeout) + +# DCI: clean up defaults +def setup_fms_config(ui_, cfg, opts): + """ INTERNAL: helper tests the fms connection. """ + + fms_id, fms_host, fms_port, timeout = get_fms_args(cfg, opts) + + ui_.status("Running FMS checks...\nChecking fms_id...\n") + if fms_id.find('@') != -1: + ui_.warn("\n") + ui_.warn(""" The FMS id should only contain the part before the '@'! + You won't be able to use fn-fmsnotify until this is fixed. + Run: hg fn-setupfms with the --fmsid argument. + +""") + elif fms_id.lower() == 'none': + ui_.warn(""" FMS id isn't set! + You won't be able to use fn-fmsnotify until this is fixed. + Run: hg fn-setupfms with the --fmsid argument. + +""") + else: + ui_.status("OK.\n\n") # hmmm... what if they manually edited the config? + + bytes = connect_to_fms(ui_, fms_host, fms_port, timeout) + if not bytes: + if not bytes is None: + ui_.warn("Connected but no response. Are you sure that's " + "an FMS server?\n") + return None + + fields = bytes.split(' ') + if fields[0] != '200': + ui_.warn("Didn't get expected response from FMS server!\n") + return None + + if not bytes.lower().find("posting allowed"): + ui_.warn("Didn't see expected 'posting allowed' message.\n") + ui_.warn("Check that FMS is setup to allow outgoing message.\n") + return None # Hmmm.. feeble, relying on message text. + else: + ui_.status("Got expected response from FMS. Looks good.\n") + + return (fms_host, fms_port, fms_id) + +def execute_setupfms(ui_, opts): + """ Execute the fn-setupfms command. """ + cfg = Config.from_ui(ui_) + result = setup_fms_config(ui_, cfg, opts) + if result: + cfg.defaults['FMS_ID'] = result[2] + cfg.defaults['FMS_HOST'] = result[0] + cfg.defaults['FMS_PORT'] = result[1] + ui_.status("""Updating config file: +fms_id = %s +fms_host = %s +fms_port = %i +""" % (result[2], result[0], result[1])) + Config.to_file(cfg) + else: + ui_.warn(""" +Run: + hg fn-setupfms +with the appropriate arguments to try to fix the problem. + +""") + diff --git a/infocalypse/infcmds.py b/infocalypse/infcmds.py --- a/infocalypse/infcmds.py +++ b/infocalypse/infcmds.py @@ -768,6 +768,7 @@ def setup_tmp_dir(ui_, tmp): ui_.warn(err) return tmp + MSG_HGRC_SET = \ """Read the config file name from the: @@ -788,8 +789,13 @@ want to re-run setup. Consider before deleting it. It may contain the *only copy* of your private key. +If you're just trying to update the FMS configuration run: + +hg fn-setupfms + +instead. + """ - def execute_setup(ui_, host, port, tmp, cfg_file = None): """ Run the setup command. """ def connection_failure(msg): @@ -797,6 +803,7 @@ def execute_setup(ui_, host, port, tmp, ui_.warn(msg) ui_.warn("It looks like your FCP host or port might be wrong.\n") ui_.warn("Set them with --fcphost and/or --fcpport and try again.\n") + raise util.Abort("Connection to FCP server failed.") # Fix defaults. if host == '': @@ -820,8 +827,7 @@ def execute_setup(ui_, host, port, tmp, tmp = setup_tmp_dir(ui_, tmp) if not is_writable(tmp): - ui_.warn("Can't write to temp dir: %s\n" % tmp) - return + raise util.Abort("Can't write to temp dir: %s\n" % tmp) # Test FCP connection. timeout_secs = 20 @@ -841,7 +847,6 @@ def execute_setup(ui_, host, port, tmp, if not connection.is_connected(): connection_failure(("\nGave up after waiting %i secs for an " + "FCP NodeHello.\n") % timeout_secs) - return ui_.status("Looks good.\nGenerating a default private key...\n") @@ -854,17 +859,14 @@ def execute_setup(ui_, host, port, tmp, except FCPError: # Protocol error. connection_failure("\nMaybe that's not an FCP server?\n") - return except socket.error: # Not an IOError until 2.6. # Horked. connection_failure("\nSocket level error.\n") - return except IOError: # Horked. connection_failure("\nSocket level error.\n") - return cfg = Config() cfg.defaults['HOST'] = host @@ -882,6 +884,8 @@ cfg file: %s Default private key: %s +The config file was successfully written! + """ % (host, port, tmp, cfg_file, default_private_key))