Example #1
0
def create_node(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >> err, "The base directory %s is not empty." % quote_local_unicode_path(
                basedir)
            print >> err, "To avoid clobbering anything, I am going to quit now."
            print >> err, "Please use a different directory, or empty this one."
            defer.returnValue(-1)
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "client")

    fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
    with open(os.path.join(basedir, "tahoe.cfg"), "w") as c:
        yield write_node_config(c, config)
        write_client_config(c, config)

    print >> out, "Node created in %s" % quote_local_unicode_path(basedir)
    tahoe_cfg = quote_local_unicode_path(os.path.join(basedir, "tahoe.cfg"))
    if not config.get("introducer", ""):
        print >> out, " Please set [client]introducer.furl= in %s!" % tahoe_cfg
        print >> out, " The node cannot connect to a grid without it."
    if not config.get("nickname", ""):
        print >> out, " Please set [node]nickname= in %s" % tahoe_cfg
    defer.returnValue(0)
Example #2
0
def create_node(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >>err, "The base directory %s is not empty." % quote_local_unicode_path(basedir)
            print >>err, "To avoid clobbering anything, I am going to quit now."
            print >>err, "Please use a different directory, or empty this one."
            defer.returnValue(-1)
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "client")

    fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
    with open(os.path.join(basedir, "tahoe.cfg"), "w") as c:
        yield write_node_config(c, config)
        write_client_config(c, config)

    print >>out, "Node created in %s" % quote_local_unicode_path(basedir)
    if not config.get("introducer", ""):
        print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
        print >>out, " The node cannot connect to a grid without it."
    if not config.get("nickname", ""):
        print >>out, " Please set [node]nickname= in tahoe.cfg"
    defer.returnValue(0)
    def __init__(self, client, local_path_u, db, name, clock, delay=0):
        self._client = client
        self._local_path_u = local_path_u
        self._local_filepath = to_filepath(local_path_u)
        self._db = db
        self._name = name
        self._clock = clock
        self._hooks = {
            'processed': None,
            'started': None,
            'iteration': None,
        }
        self.started_d = self.set_hook('started')

        if not self._local_filepath.exists():
            raise AssertionError("The '[magic_folder] local.directory' parameter was %s "
                                 "but there is no directory at that location."
                                 % quote_local_unicode_path(self._local_path_u))
        if not self._local_filepath.isdir():
            raise AssertionError("The '[magic_folder] local.directory' parameter was %s "
                                 "but the thing at that location is not a directory."
                                 % quote_local_unicode_path(self._local_path_u))

        self._deque = deque()
        # do we also want to bound on "maximum age"?
        self._process_history = deque(maxlen=20)
        self._stopped = False
        # XXX pass in an initial value for this; it seems like .10 broke this and it's always 0
        self._turn_delay = delay
        self._log('delay is %f' % self._turn_delay)

        # a Deferred to wait for the _do_processing() loop to exit
        # (gets set to the return from _do_processing() if we get that
        # far)
        self._processing = defer.succeed(None)
Example #4
0
    def upload(self, childpath):
        precondition_abspath(childpath)

        #self.verboseprint("uploading %s.." % quote_local_unicode_path(childpath))
        metadata = get_local_metadata(childpath)

        # we can use the backupdb here
        must_upload, bdb_results = self.check_backupdb_file(childpath)

        if must_upload:
            self.verboseprint("uploading %s.." %
                              quote_local_unicode_path(childpath))
            infileobj = open(childpath, "rb")
            url = self.options['node-url'] + "uri"
            resp = do_http("PUT", url, infileobj)
            if resp.status not in (200, 201):
                raise HTTPError("Error during file PUT", resp)

            filecap = resp.read().strip()
            self.verboseprint(
                " %s -> %s" %
                (quote_local_unicode_path(childpath, quotemarks=False),
                 quote_output(filecap, quotemarks=False)))
            #self.verboseprint(" metadata: %s" % (quote_output(metadata, quotemarks=False),))

            if bdb_results:
                bdb_results.did_upload(filecap)

            return True, filecap, metadata

        else:
            self.verboseprint("skipping %s.." %
                              quote_local_unicode_path(childpath))
            return False, bdb_results.was_uploaded(), metadata
Example #5
0
def create_introducer(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >> err, "The base directory %s is not empty." % quote_local_unicode_path(
                basedir)
            print >> err, "To avoid clobbering anything, I am going to quit now."
            print >> err, "Please use a different directory, or empty this one."
            defer.returnValue(-1)
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "introducer")

    fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
    with open(os.path.join(basedir, "tahoe.cfg"), "w") as c:
        yield write_node_config(c, config)

    print >> out, "Introducer created in %s" % quote_local_unicode_path(
        basedir)
    defer.returnValue(0)
Example #6
0
    def upload(self, childpath):
        precondition_abspath(childpath)

        #self.verboseprint("uploading %s.." % quote_local_unicode_path(childpath))
        metadata = get_local_metadata(childpath)

        # we can use the backupdb here
        must_upload, bdb_results = self.check_backupdb_file(childpath)

        if must_upload:
            self.verboseprint("uploading %s.." % quote_local_unicode_path(childpath))
            infileobj = open(childpath, "rb")
            url = self.options['node-url'] + "uri"
            resp = do_http("PUT", url, infileobj)
            if resp.status not in (200, 201):
                raise HTTPError("Error during file PUT", resp)

            filecap = resp.read().strip()
            self.verboseprint(" %s -> %s" % (quote_local_unicode_path(childpath, quotemarks=False),
                                             quote_output(filecap, quotemarks=False)))
            #self.verboseprint(" metadata: %s" % (quote_output(metadata, quotemarks=False),))

            if bdb_results:
                bdb_results.did_upload(filecap)

            return True, filecap, metadata

        else:
            self.verboseprint("skipping %s.." % quote_local_unicode_path(childpath))
            return False, bdb_results.was_uploaded(), metadata
Example #7
0
    def __init__(self, client, local_path_u, db, name, clock):
        self._client = client
        self._local_path_u = local_path_u
        self._local_filepath = to_filepath(local_path_u)
        self._db = db
        self._name = name
        self._clock = clock
        self._debug_log = False
        self._logger = None
        self._hooks = {
            'processed': None,
            'started': None,
            'iteration': None,
            'inotify': None,
        }
        self.started_d = self.set_hook('started')

        if not self._local_filepath.exists():
            raise AssertionError("The '[magic_folder] local.directory' parameter was %s "
                                 "but there is no directory at that location."
                                 % quote_local_unicode_path(self._local_path_u))
        if not self._local_filepath.isdir():
            raise AssertionError("The '[magic_folder] local.directory' parameter was %s "
                                 "but the thing at that location is not a directory."
                                 % quote_local_unicode_path(self._local_path_u))

        self._deque = deque()
        # do we also want to bound on "maximum age"?
        self._process_history = deque(maxlen=20)
        self._stopped = False

        # a Deferred to wait for the _do_processing() loop to exit
        # (gets set to the return from _do_processing() if we get that
        # far)
        self._processing = defer.succeed(None)
Example #8
0
 def upload_directory(self, path, compare_contents, create_contents):
     must_create, r = self.check_backupdb_directory(compare_contents)
     if must_create:
         self.verboseprint(" creating directory for %s" % quote_local_unicode_path(path))
         newdircap = mkdir(create_contents, self.options)
         assert isinstance(newdircap, str)
         if r:
             r.did_create(newdircap)
         return True, newdircap
     else:
         self.verboseprint(" re-using old directory for %s" % quote_local_unicode_path(path))
         return False, r.was_created()
Example #9
0
 def upload_directory(self, path, compare_contents, create_contents):
     must_create, r = self.check_backupdb_directory(compare_contents)
     if must_create:
         self.verboseprint(" creating directory for %s" % quote_local_unicode_path(path))
         newdircap = mkdir(create_contents, self.options)
         assert isinstance(newdircap, str)
         if r:
             r.did_create(newdircap)
         return True, newdircap
     else:
         self.verboseprint(" re-using old directory for %s" % quote_local_unicode_path(path))
         return False, r.was_created()
Example #10
0
def _leave(node_directory, name, existing_folders):
    privdir = os.path.join(node_directory, u"private")
    db_fname = os.path.join(privdir, u"magicfolder_{}.sqlite".format(name))

    # delete from YAML file and re-write it
    del existing_folders[name]
    save_magic_folders(node_directory, existing_folders)

    # delete the database file
    try:
        fileutil.remove(db_fname)
    except Exception as e:
        raise Exception(
            "unable to remove %s due to %s: %s" %
            (quote_local_unicode_path(db_fname), e.__class__.__name__, str(e)))

    # if this was the last magic-folder, disable them entirely
    if not existing_folders:
        parser = SafeConfigParser()
        parser.read(os.path.join(node_directory, u"tahoe.cfg"))
        parser.remove_section("magic_folder")
        with open(os.path.join(node_directory, u"tahoe.cfg"), "w") as f:
            parser.write(f)

    return 0
Example #11
0
def leave(options):
    from ConfigParser import SafeConfigParser

    dmd_cap_file = os.path.join(options["node-directory"], u"private",
                                u"magic_folder_dircap")
    collective_readcap_file = os.path.join(options["node-directory"],
                                           u"private", u"collective_dircap")
    magic_folder_db_file = os.path.join(options["node-directory"], u"private",
                                        u"magicfolderdb.sqlite")

    parser = SafeConfigParser()
    parser.read(os.path.join(options["node-directory"], u"tahoe.cfg"))
    parser.remove_section("magic_folder")
    f = open(os.path.join(options["node-directory"], u"tahoe.cfg"), "w")
    parser.write(f)
    f.close()

    for f in [dmd_cap_file, collective_readcap_file, magic_folder_db_file]:
        try:
            fileutil.remove(f)
        except Exception as e:
            print >> options.stderr, (
                "Warning: unable to remove %s due to %s: %s" %
                (quote_local_unicode_path(f), e.__class__.__name__, str(e)))
    # if this doesn't return 0, then the CLI stuff fails
    return 0
def stop(config, out=sys.stdout, err=sys.stderr):
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >>out, "STOPPING", quoted_basedir
    pidfile = os.path.join(basedir, u"twistd.pid")
    if not os.path.exists(pidfile):
        print >>err, "%s does not look like a running node directory (no twistd.pid)" % quoted_basedir
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2
    pid = open(pidfile, "r").read()
    pid = int(pid)

    # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
    # process itself to go away. If it hasn't gone away after 20 seconds, warn
    # the user but keep waiting until they give up.
    try:
        os.kill(pid, signal.SIGKILL)
    except OSError, oserr:
        if oserr.errno == 3:
            print oserr.strerror
            # the process didn't exist, so wipe the pid file
            os.remove(pidfile)
            return 2
        else:
            raise
Example #13
0
def find_shares(options):
    """Given a storage index and a list of node directories, emit a list of
    all matching shares to stdout, one per line. For example:

     find-shares.py 44kai1tui348689nrw8fjegc8c ~/testnet/node-*

    gives:

    /home/warner/testnet/node-1/storage/shares/44k/44kai1tui348689nrw8fjegc8c/5
    /home/warner/testnet/node-1/storage/shares/44k/44kai1tui348689nrw8fjegc8c/9
    /home/warner/testnet/node-2/storage/shares/44k/44kai1tui348689nrw8fjegc8c/2
    """
    from allmydata.storage.server import si_a2b, storage_index_to_dir
    from allmydata.util.encodingutil import listdir_unicode, quote_local_unicode_path

    out = options.stdout
    sharedir = storage_index_to_dir(si_a2b(options.si_s.encode("utf-8")))
    for d in options.nodedirs:
        d = os.path.join(d, "storage", "shares", sharedir)
        if os.path.exists(d):
            for shnum in listdir_unicode(d):
                print(quote_local_unicode_path(os.path.join(d, shnum),
                                               quotemarks=False),
                      file=out)

    return 0
def start(config, out=sys.stdout, err=sys.stderr):
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >>out, "STARTING", quoted_basedir
    if not os.path.isdir(basedir):
        print >>err, "%s does not look like a directory at all" % quoted_basedir
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print >>err, "%s is not a recognizable node directory" % quoted_basedir
        return 1
    # Now prepare to turn into a twistd process. This os.chdir is the point
    # of no return.
    os.chdir(basedir)
    twistd_args = []
    if (nodetype in ("client", "introducer")
        and "--nodaemon" not in config.twistd_args
        and "--syslog" not in config.twistd_args
        and "--logfile" not in config.twistd_args):
        fileutil.make_dirs(os.path.join(basedir, u"logs"))
        twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
    twistd_args.extend(config.twistd_args)
    twistd_args.append("StartTahoeNode") # point at our StartTahoeNodePlugin

    twistd_config = MyTwistdConfig()
    try:
        twistd_config.parseOptions(twistd_args)
    except usage.error, ue:
        # these arguments were unsuitable for 'twistd'
        print >>err, config
        print >>err, "tahoe %s: usage error from twistd: %s\n" % (config.subcommand_name, ue)
        return 1
Example #15
0
class StartOptions(BasedirOptions):
    subcommand_name = "start"
    optParameters = [
        ("basedir", "C", None,
         "Specify which Tahoe base directory should be used."
         " This has the same effect as the global --node-directory option."
         " [default: %s]" % quote_local_unicode_path(_default_nodedir)),
        ]

    def parseArgs(self, basedir=None, *twistd_args):
        # This can't handle e.g. 'tahoe start --nodaemon', since '--nodaemon'
        # looks like an option to the tahoe subcommand, not to twistd. So you
        # can either use 'tahoe start' or 'tahoe start NODEDIR
        # --TWISTD-OPTIONS'. Note that 'tahoe --node-directory=NODEDIR start
        # --TWISTD-OPTIONS' also isn't allowed, unfortunately.

        BasedirOptions.parseArgs(self, basedir)
        self.twistd_args = twistd_args

    def getSynopsis(self):
        return ("Usage:  %s [global-options] %s [options]"
                " [NODEDIR [twistd-options]]"
                % (self.command_name, self.subcommand_name))

    def getUsage(self, width=None):
        t = BasedirOptions.getUsage(self, width) + "\n"
        twistd_options = str(MyTwistdConfig()).partition("\n")[2].partition("\n\n")[0]
        t += twistd_options.replace("Options:", "twistd-options:", 1)
        t += """

Note that if any twistd-options are used, NODEDIR must be specified explicitly
(not by default or using -C/--basedir or -d/--node-directory), and followed by
the twistd-options.
"""
        return t
Example #16
0
def start(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >> out, "STARTING", quoted_basedir
    if not os.path.isdir(basedir):
        print >> err, "%s does not look like a directory at all" % quoted_basedir
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print >> err, "%s is not a recognizable node directory" % quoted_basedir
        return 1
    # Now prepare to turn into a twistd process. This os.chdir is the point
    # of no return.
    os.chdir(basedir)
    twistd_args = []
    if (nodetype in ("client", "introducer")
            and "--nodaemon" not in config.twistd_args
            and "--syslog" not in config.twistd_args
            and "--logfile" not in config.twistd_args):
        fileutil.make_dirs(os.path.join(basedir, u"logs"))
        twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
    twistd_args.extend(config.twistd_args)
    twistd_args.append("StartTahoeNode")  # point at our StartTahoeNodePlugin

    twistd_config = MyTwistdConfig()
    try:
        twistd_config.parseOptions(twistd_args)
    except usage.error, ue:
        # these arguments were unsuitable for 'twistd'
        print >> err, config
        print >> err, "tahoe %s: usage error from twistd: %s\n" % (
            config.subcommand_name, ue)
        return 1
Example #17
0
class BasedirOptions(BaseOptions):
    default_nodedir = _default_nodedir

    optParameters = [
        ["basedir", "C", None, "Specify which Tahoe base directory should be used. [default: %s]"
         % quote_local_unicode_path(_default_nodedir)],
    ]

    def parseArgs(self, basedir=None):
        if self.parent['node-directory'] and self['basedir']:
            raise usage.UsageError("The --node-directory (or -d) and --basedir (or -C) options cannot both be used.")
        if self.parent['node-directory'] and basedir:
            raise usage.UsageError("The --node-directory (or -d) option and a basedir argument cannot both be used.")
        if self['basedir'] and basedir:
            raise usage.UsageError("The --basedir (or -C) option and a basedir argument cannot both be used.")

        if basedir:
            b = argv_to_abspath(basedir)
        elif self['basedir']:
            b = argv_to_abspath(self['basedir'])
        elif self.parent['node-directory']:
            b = argv_to_abspath(self.parent['node-directory'])
        elif self.default_nodedir:
            b = self.default_nodedir
        else:
            raise usage.UsageError("No default basedir available, you must provide one with --node-directory, --basedir, or a basedir argument")
        self['basedir'] = b

    def postOptions(self):
        if not self['basedir']:
            raise usage.UsageError("A base directory for the node must be provided.")
Example #18
0
class CreateClientOptions(_CreateBaseOptions):
    synopsis = "[options] [NODEDIR]"
    description = "Create a client-only Tahoe-LAFS node (no storage server)."

    optParameters = [
        # we provide 'create-node'-time options for the most common
        # configuration knobs. The rest can be controlled by editing
        # tahoe.cfg before node startup.
        ("nickname", "n", None, "Specify the nickname for this node."),
        ("introducer", "i", None, "Specify the introducer FURL to use."),
        ("webport", "p", "tcp:3456:interface=127.0.0.1",
         "Specify which TCP port to run the HTTP interface on. Use 'none' to disable."
         ),
        ("basedir", "C", None,
         "Specify which Tahoe base directory should be used. This has the same effect as the global --node-directory option. [default: %s]"
         % quote_local_unicode_path(_default_nodedir)),
        ("shares-needed", None, 3,
         "Needed shares required for uploaded files."),
        ("shares-happy", None, 7,
         "How many servers new files must be placed on."),
        ("shares-total", None, 10,
         "Total shares required for uploaded files."),
    ]

    # This is overridden in order to ensure we get a "Wrong number of
    # arguments." error when more than one argument is given.
    def parseArgs(self, basedir=None):
        BasedirOptions.parseArgs(self, basedir)
        for name in ["shares-needed", "shares-happy", "shares-total"]:
            try:
                int(self[name])
            except ValueError:
                raise UsageError("--{} must be an integer".format(name))
Example #19
0
def stop(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >> out, "STOPPING", quoted_basedir
    pidfile = get_pidfile(basedir)
    pid = get_pid_from_pidfile(pidfile)
    if pid is None:
        print >> err, "%s does not look like a running node directory (no twistd.pid)" % quoted_basedir
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2
    elif pid == -1:
        print >> err, "%s contains an invalid PID file" % basedir
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2

    # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
    # process itself to go away. If it hasn't gone away after 20 seconds, warn
    # the user but keep waiting until they give up.
    try:
        os.kill(pid, signal.SIGKILL)
    except OSError, oserr:
        if oserr.errno == 3:
            print oserr.strerror
            # the process didn't exist, so wipe the pid file
            os.remove(pidfile)
            return COULD_NOT_STOP
        else:
            raise
Example #20
0
def stop(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >> out, "STOPPING", quoted_basedir
    pidfile = os.path.join(basedir, u"twistd.pid")
    if not os.path.exists(pidfile):
        print >> err, "%s does not look like a running node directory (no twistd.pid)" % quoted_basedir
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2
    with open(pidfile, "r") as f:
        pid = f.read()
    pid = int(pid)

    # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
    # process itself to go away. If it hasn't gone away after 20 seconds, warn
    # the user but keep waiting until they give up.
    try:
        os.kill(pid, signal.SIGKILL)
    except OSError, oserr:
        if oserr.errno == 3:
            print oserr.strerror
            # the process didn't exist, so wipe the pid file
            os.remove(pidfile)
            return 2
        else:
            raise
Example #21
0
def run(config):
    """
    Runs a Tahoe-LAFS node in the foreground.

    Sets up the IService instance corresponding to the type of node
    that's starting and uses Twisted's twistd runner to disconnect our
    process from the terminal.
    """
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print("'tahoe {}' in {}".format(config.subcommand_name, quoted_basedir),
          file=out)
    if not os.path.isdir(basedir):
        print("%s does not look like a directory at all" % quoted_basedir,
              file=err)
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print("%s is not a recognizable node directory" % quoted_basedir,
              file=err)
        return 1
    # Now prepare to turn into a twistd process. This os.chdir is the point
    # of no return.
    os.chdir(basedir)
    twistd_args = ["--nodaemon"]
    twistd_args.extend(config.twistd_args)
    twistd_args.append(
        "DaemonizeTahoeNode")  # point at our DaemonizeTahoeNodePlugin

    twistd_config = MyTwistdConfig()
    twistd_config.stdout = out
    twistd_config.stderr = err
    try:
        twistd_config.parseOptions(twistd_args)
    except usage.error as ue:
        # these arguments were unsuitable for 'twistd'
        print(config, file=err)
        print("tahoe %s: usage error from twistd: %s\n" %
              (config.subcommand_name, ue),
              file=err)
        return 1
    twistd_config.loadedPlugins = {
        "DaemonizeTahoeNode": DaemonizeTahoeNodePlugin(nodetype, basedir)
    }

    # handle invalid PID file (twistd might not start otherwise)
    pidfile = get_pidfile(basedir)
    if get_pid_from_pidfile(pidfile) == -1:
        print("found invalid PID file in %s - deleting it" % basedir, file=err)
        os.remove(pidfile)

    # We always pass --nodaemon so twistd.runApp does not daemonize.
    print("running node in %s" % (quoted_basedir, ), file=out)
    twistd.runApp(twistd_config)
    return 0
    def process(self, localpath):
        precondition_abspath(localpath)
        # returns newdircap

        quoted_path = quote_local_unicode_path(localpath)
        self.verboseprint("processing %s" % (quoted_path,))
        create_contents = {} # childname -> (type, rocap, metadata)
        compare_contents = {} # childname -> rocap

        try:
            children = listdir_unicode(localpath)
        except EnvironmentError:
            self.directories_skipped += 1
            self.warn("WARNING: permission denied on directory %s" % (quoted_path,))
            children = []
        except FilenameEncodingError:
            self.directories_skipped += 1
            self.warn("WARNING: could not list directory %s due to a filename encoding error" % (quoted_path,))
            children = []

        for child in self.options.filter_listdir(children):
            assert isinstance(child, unicode), child
            childpath = os.path.join(localpath, child)
            # note: symlinks to directories are both islink() and isdir()
            if os.path.isdir(childpath) and not os.path.islink(childpath):
                metadata = get_local_metadata(childpath)
                # recurse on the child directory
                childcap = self.process(childpath)
                assert isinstance(childcap, str)
                create_contents[child] = ("dirnode", childcap, metadata)
                compare_contents[child] = childcap
            elif os.path.isfile(childpath) and not os.path.islink(childpath):
                try:
                    childcap, metadata = self.upload(childpath)
                    assert isinstance(childcap, str)
                    create_contents[child] = ("filenode", childcap, metadata)
                    compare_contents[child] = childcap
                except EnvironmentError:
                    self.files_skipped += 1
                    self.warn("WARNING: permission denied on file %s" % quote_local_unicode_path(childpath))
            else:
                self.files_skipped += 1
                if os.path.islink(childpath):
                    self.warn("WARNING: cannot backup symlink %s" % quote_local_unicode_path(childpath))
                else:
                    self.warn("WARNING: cannot backup special file %s" % quote_local_unicode_path(childpath))

        must_create, r = self.check_backupdb_directory(compare_contents)
        if must_create:
            self.verboseprint(" creating directory for %s" % quote_local_unicode_path(localpath))
            newdircap = mkdir(create_contents, self.options)
            assert isinstance(newdircap, str)
            if r:
                r.did_create(newdircap)
            self.directories_created += 1
            return newdircap
        else:
            self.verboseprint(" re-using old directory for %s" % quote_local_unicode_path(localpath))
            self.directories_reused += 1
            return r.was_created()
Example #23
0
    def process(self, localpath):
        precondition_abspath(localpath)
        # returns newdircap

        quoted_path = quote_local_unicode_path(localpath)
        self.verboseprint("processing %s" % (quoted_path,))
        create_contents = {} # childname -> (type, rocap, metadata)
        compare_contents = {} # childname -> rocap

        try:
            children = listdir_unicode(localpath)
        except EnvironmentError:
            self.directories_skipped += 1
            self.warn("WARNING: permission denied on directory %s" % (quoted_path,))
            children = []
        except FilenameEncodingError:
            self.directories_skipped += 1
            self.warn("WARNING: could not list directory %s due to a filename encoding error" % (quoted_path,))
            children = []

        for child in self.options.filter_listdir(children):
            assert isinstance(child, unicode), child
            childpath = os.path.join(localpath, child)
            # note: symlinks to directories are both islink() and isdir()
            if os.path.isdir(childpath) and not os.path.islink(childpath):
                metadata = get_local_metadata(childpath)
                # recurse on the child directory
                childcap = self.process(childpath)
                assert isinstance(childcap, str)
                create_contents[child] = ("dirnode", childcap, metadata)
                compare_contents[child] = childcap
            elif os.path.isfile(childpath) and not os.path.islink(childpath):
                try:
                    childcap, metadata = self.upload(childpath)
                    assert isinstance(childcap, str)
                    create_contents[child] = ("filenode", childcap, metadata)
                    compare_contents[child] = childcap
                except EnvironmentError:
                    self.files_skipped += 1
                    self.warn("WARNING: permission denied on file %s" % quote_local_unicode_path(childpath))
            else:
                self.files_skipped += 1
                if os.path.islink(childpath):
                    self.warn("WARNING: cannot backup symlink %s" % quote_local_unicode_path(childpath))
                else:
                    self.warn("WARNING: cannot backup special file %s" % quote_local_unicode_path(childpath))

        must_create, r = self.check_backupdb_directory(compare_contents)
        if must_create:
            self.verboseprint(" creating directory for %s" % quote_local_unicode_path(localpath))
            newdircap = mkdir(create_contents, self.options)
            assert isinstance(newdircap, str)
            if r:
                r.did_create(newdircap)
            self.directories_created += 1
            return newdircap
        else:
            self.verboseprint(" re-using old directory for %s" % quote_local_unicode_path(localpath))
            self.directories_reused += 1
            return r.was_created()
Example #24
0
    def test_quote_path(self):
        self.failUnlessReallyEqual(quote_path([u'foo', u'bar']), b"'foo/bar'")
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'bar'], quotemarks=True), b"'foo/bar'")
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'bar'], quotemarks=False), b"foo/bar")
        self.failUnlessReallyEqual(quote_path([u'foo', u'\nbar']),
                                   b'"foo/\\x0abar"')
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'\nbar'], quotemarks=True), b'"foo/\\x0abar"')
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'\nbar'], quotemarks=False),
            b'"foo/\\x0abar"')

        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo"),
            win32_other(b"'C:\\foo'", b"'\\\\?\\C:\\foo'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=True),
            win32_other(b"'C:\\foo'", b"'\\\\?\\C:\\foo'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=False),
            win32_other(b"C:\\foo", b"\\\\?\\C:\\foo"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar"),
            win32_other(b"'\\\\foo\\bar'", b"'\\\\?\\UNC\\foo\\bar'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar", quotemarks=True),
            win32_other(b"'\\\\foo\\bar'", b"'\\\\?\\UNC\\foo\\bar'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar",
                                     quotemarks=False),
            win32_other(b"\\\\foo\\bar", b"\\\\?\\UNC\\foo\\bar"))
Example #25
0
    def test_quote_path(self):
        self.failUnlessReallyEqual(quote_path([u'foo', u'bar']), "'foo/bar'")
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'bar'], quotemarks=True), "'foo/bar'")
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'bar'], quotemarks=False), "foo/bar")
        self.failUnlessReallyEqual(quote_path([u'foo', u'\nbar']),
                                   '"foo/\\x0abar"')
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'\nbar'], quotemarks=True), '"foo/\\x0abar"')
        self.failUnlessReallyEqual(
            quote_path([u'foo', u'\nbar'], quotemarks=False), '"foo/\\x0abar"')

        def win32_other(win32, other):
            return win32 if sys.platform == "win32" else other

        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo"),
            win32_other("'C:\\foo'", "'\\\\?\\C:\\foo'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=True),
            win32_other("'C:\\foo'", "'\\\\?\\C:\\foo'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=False),
            win32_other("C:\\foo", "\\\\?\\C:\\foo"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar"),
            win32_other("'\\\\foo\\bar'", "'\\\\?\\UNC\\foo\\bar'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar", quotemarks=True),
            win32_other("'\\\\foo\\bar'", "'\\\\?\\UNC\\foo\\bar'"))
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar",
                                     quotemarks=False),
            win32_other("\\\\foo\\bar", "\\\\?\\UNC\\foo\\bar"))
    def test_quote_path(self):
        self.failUnlessReallyEqual(quote_path([u"foo", u"bar"]), "'foo/bar'")
        self.failUnlessReallyEqual(quote_path([u"foo", u"bar"], quotemarks=True), "'foo/bar'")
        self.failUnlessReallyEqual(quote_path([u"foo", u"bar"], quotemarks=False), "foo/bar")
        self.failUnlessReallyEqual(quote_path([u"foo", u"\nbar"]), '"foo/\\x0abar"')
        self.failUnlessReallyEqual(quote_path([u"foo", u"\nbar"], quotemarks=True), '"foo/\\x0abar"')
        self.failUnlessReallyEqual(quote_path([u"foo", u"\nbar"], quotemarks=False), '"foo/\\x0abar"')

        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo"), win32_other("'C:\\foo'", "'\\\\?\\C:\\foo'")
        )
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=True), win32_other("'C:\\foo'", "'\\\\?\\C:\\foo'")
        )
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=False), win32_other("C:\\foo", "\\\\?\\C:\\foo")
        )
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar"), win32_other("'\\\\foo\\bar'", "'\\\\?\\UNC\\foo\\bar'")
        )
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar", quotemarks=True),
            win32_other("'\\\\foo\\bar'", "'\\\\?\\UNC\\foo\\bar'"),
        )
        self.failUnlessReallyEqual(
            quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar", quotemarks=False),
            win32_other("\\\\foo\\bar", "\\\\?\\UNC\\foo\\bar"),
        )
Example #27
0
def create_introducer(config, out=sys.stdout, err=sys.stderr):
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >>err, "The base directory %s is not empty." % quote_local_unicode_path(basedir)
            print >>err, "To avoid clobbering anything, I am going to quit now."
            print >>err, "Please use a different directory, or empty this one."
            return -1
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "introducer")

    c = open(os.path.join(basedir, "tahoe.cfg"), "w")
    write_node_config(c, config)
    c.close()

    print >>out, "Introducer created in %s" % quote_local_unicode_path(basedir)
    return 0
Example #28
0
 def opt_exclude_from(self, filepath):
     """Ignore file matching glob patterns listed in file, one per
     line. The file is assumed to be in the argv encoding."""
     abs_filepath = argv_to_abspath(filepath)
     try:
         exclude_file = open(abs_filepath)
     except:
         raise BackupConfigurationError('Error opening exclude file %s.' % quote_local_unicode_path(abs_filepath))
     try:
         for line in exclude_file:
             self.opt_exclude(line)
     finally:
         exclude_file.close()
Example #29
0
 def opt_exclude_from(self, filepath):
     """Ignore file matching glob patterns listed in file, one per
     line. The file is assumed to be in the argv encoding."""
     abs_filepath = argv_to_abspath(filepath)
     try:
         exclude_file = file(abs_filepath)
     except:
         raise BackupConfigurationError('Error opening exclude file %s.' % quote_local_unicode_path(abs_filepath))
     try:
         for line in exclude_file:
             self.opt_exclude(line)
     finally:
         exclude_file.close()
Example #30
0
def create_introducer(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print("The base directory %s is not empty." % quote_local_unicode_path(basedir), file=err)
            print("To avoid clobbering anything, I am going to quit now.", file=err)
            print("Please use a different directory, or empty this one.", file=err)
            defer.returnValue(-1)
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "introducer")

    fileutil.make_dirs(os.path.join(basedir, "private"), 0o700)
    with open(os.path.join(basedir, "tahoe.cfg"), "w") as c:
        yield write_node_config(c, config)

    print("Introducer created in %s" % quote_local_unicode_path(basedir), file=out)
    defer.returnValue(0)
Example #31
0
    def __init__(self, basedir=u".", verbose=True):
        self.verbose = verbose
        StatsGatherer.__init__(self, basedir)
        self.picklefile = os.path.join(basedir, "stats.pickle")

        if os.path.exists(self.picklefile):
            f = open(self.picklefile, 'rb')
            try:
                self.gathered_stats = pickle.load(f)
            except Exception:
                print ("Error while attempting to load pickle file %s.\n"
                       "You may need to restore this file from a backup, or delete it if no backup is available.\n" %
                       quote_local_unicode_path(self.picklefile))
                raise
            f.close()
        else:
            self.gathered_stats = {}
Example #32
0
    def __init__(self, basedir=u".", verbose=True):
        self.verbose = verbose
        StatsGatherer.__init__(self, basedir)
        self.jsonfile = os.path.join(basedir, "stats.json")

        if os.path.exists(self.jsonfile):
            try:
                with open(self.jsonfile, 'rb') as f:
                    self.gathered_stats = json.load(f)
            except Exception:
                print("Error while attempting to load stats file %s.\n"
                      "You may need to restore this file from a backup,"
                      " or delete it if no backup is available.\n" %
                      quote_local_unicode_path(self.jsonfile))
                raise
        else:
            self.gathered_stats = {}
Example #33
0
class _CreateBaseOptions(BasedirOptions):
    optParameters = [
        # we provide 'create-node'-time options for the most common
        # configuration knobs. The rest can be controlled by editing
        # tahoe.cfg before node startup.
        ("nickname", "n", None, "Specify the nickname for this node."),
        ("introducer", "i", None, "Specify the introducer FURL to use."),
        ("webport", "p", "tcp:3456:interface=127.0.0.1",
         "Specify which TCP port to run the HTTP interface on. Use 'none' to disable."),
        ("basedir", "C", None, "Specify which Tahoe base directory should be used. This has the same effect as the global --node-directory option. [default: %s]"
         % quote_local_unicode_path(_default_nodedir)),

        ]

    # This is overridden in order to ensure we get a "Wrong number of
    # arguments." error when more than one argument is given.
    def parseArgs(self, basedir=None):
        BasedirOptions.parseArgs(self, basedir)
Example #34
0
        def do_update_db(written_abspath_u):
            filecap = item.file_node.get_uri()
            last_uploaded_uri = item.metadata.get('last_uploaded_uri', None)
            self._log("DOUPDATEDB %r" % written_abspath_u)
            last_downloaded_uri = filecap
            last_downloaded_timestamp = now
            written_pathinfo = get_pathinfo(written_abspath_u)

            if not written_pathinfo.exists and not item.metadata.get('deleted', False):
                raise Exception("downloaded object %s disappeared" % quote_local_unicode_path(written_abspath_u))

            self._db.did_upload_version(
                item.relpath_u, item.metadata['version'], last_uploaded_uri,
                last_downloaded_uri, last_downloaded_timestamp, written_pathinfo,
            )
            self._count('objects_downloaded')
            item.set_status('success', self._clock.seconds())
            return True
        def do_update_db(written_abspath_u):
            filecap = item.file_node.get_uri()
            last_uploaded_uri = item.metadata.get('last_uploaded_uri', None)
            self._log("DOUPDATEDB %r" % written_abspath_u)
            last_downloaded_uri = filecap
            last_downloaded_timestamp = now
            written_pathinfo = get_pathinfo(written_abspath_u)

            if not written_pathinfo.exists and not item.metadata.get('deleted', False):
                raise Exception("downloaded object %s disappeared" % quote_local_unicode_path(written_abspath_u))

            self._db.did_upload_version(
                item.relpath_u, item.metadata['version'], last_uploaded_uri,
                last_downloaded_uri, last_downloaded_timestamp, written_pathinfo,
            )
            self._count('objects_downloaded')
            item.set_status('success', self._clock.seconds())
            return True
Example #36
0
def daemonize(config):
    """
    Runs the 'tahoe daemonize' command.

    Sets up the IService instance corresponding to the type of node
    that's starting and uses Twisted's twistd runner to disconnect our
    process from the terminal.
    """
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >> out, "daemonizing in {}".format(quoted_basedir)
    if not os.path.isdir(basedir):
        print >> err, "%s does not look like a directory at all" % quoted_basedir
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print >> err, "%s is not a recognizable node directory" % quoted_basedir
        return 1
    # Now prepare to turn into a twistd process. This os.chdir is the point
    # of no return.
    os.chdir(basedir)
    twistd_args = []
    if (nodetype in (u"client", u"introducer")
            and "--nodaemon" not in config.twistd_args
            and "--syslog" not in config.twistd_args
            and "--logfile" not in config.twistd_args):
        fileutil.make_dirs(os.path.join(basedir, u"logs"))
        twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
    twistd_args.extend(config.twistd_args)
    twistd_args.append(
        "DaemonizeTahoeNode")  # point at our DaemonizeTahoeNodePlugin

    twistd_config = MyTwistdConfig()
    try:
        twistd_config.parseOptions(twistd_args)
    except usage.error, ue:
        # these arguments were unsuitable for 'twistd'
        print >> err, config
        print >> err, "tahoe %s: usage error from twistd: %s\n" % (
            config.subcommand_name, ue)
        return 1
Example #37
0
def leave(options):
    from ConfigParser import SafeConfigParser

    existing_folders = load_magic_folders(options["node-directory"])

    if not existing_folders:
        print("No magic-folders at all", file=options.stderr)
        return 1

    if options["name"] not in existing_folders:
        print("No such magic-folder '{}'".format(options["name"]),
              file=options.stderr)
        return 1

    privdir = os.path.join(options["node-directory"], u"private")
    db_fname = os.path.join(privdir,
                            u"magicfolder_{}.sqlite".format(options["name"]))

    # delete from YAML file and re-write it
    del existing_folders[options["name"]]
    save_magic_folders(options["node-directory"], existing_folders)

    # delete the database file
    try:
        fileutil.remove(db_fname)
    except Exception as e:
        print(
            "Warning: unable to remove %s due to %s: %s" %
            (quote_local_unicode_path(db_fname), e.__class__.__name__, str(e)),
            file=options.stderr)

    # if this was the last magic-folder, disable them entirely
    if not existing_folders:
        parser = SafeConfigParser()
        parser.read(os.path.join(options["node-directory"], u"tahoe.cfg"))
        parser.remove_section("magic_folder")
        with open(os.path.join(options["node-directory"], u"tahoe.cfg"),
                  "w") as f:
            parser.write(f)

    return 0
Example #38
0
def daemonize(config):
    """
    Runs the 'tahoe daemonize' command.

    Sets up the IService instance corresponding to the type of node
    that's starting and uses Twisted's twistd runner to disconnect our
    process from the terminal.
    """
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >>out, "daemonizing in {}".format(quoted_basedir)
    if not os.path.isdir(basedir):
        print >>err, "%s does not look like a directory at all" % quoted_basedir
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print >>err, "%s is not a recognizable node directory" % quoted_basedir
        return 1
    # Now prepare to turn into a twistd process. This os.chdir is the point
    # of no return.
    os.chdir(basedir)
    twistd_args = []
    if (nodetype in (u"client", u"introducer")
        and "--nodaemon" not in config.twistd_args
        and "--syslog" not in config.twistd_args
        and "--logfile" not in config.twistd_args):
        fileutil.make_dirs(os.path.join(basedir, u"logs"))
        twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
    twistd_args.extend(config.twistd_args)
    twistd_args.append("DaemonizeTahoeNode") # point at our DaemonizeTahoeNodePlugin

    twistd_config = MyTwistdConfig()
    try:
        twistd_config.parseOptions(twistd_args)
    except usage.error, ue:
        # these arguments were unsuitable for 'twistd'
        print >>err, config
        print >>err, "tahoe %s: usage error from twistd: %s\n" % (config.subcommand_name, ue)
        return 1
Example #39
0
def leave(options):
    from ConfigParser import SafeConfigParser

    dmd_cap_file = os.path.join(options["node-directory"], u"private", u"magic_folder_dircap")
    collective_readcap_file = os.path.join(options["node-directory"], u"private", u"collective_dircap")
    magic_folder_db_file = os.path.join(options["node-directory"], u"private", u"magicfolderdb.sqlite")

    parser = SafeConfigParser()
    parser.read(os.path.join(options["node-directory"], u"tahoe.cfg"))
    parser.remove_section("magic_folder")
    f = open(os.path.join(options["node-directory"], u"tahoe.cfg"), "w")
    parser.write(f)
    f.close()

    for f in [dmd_cap_file, collective_readcap_file, magic_folder_db_file]:
        try:
            fileutil.remove(f)
        except Exception as e:
            print >>options.stderr, ("Warning: unable to remove %s due to %s: %s"
                % (quote_local_unicode_path(f), e.__class__.__name__, str(e)))
    # if this doesn't return 0, then the CLI stuff fails
    return 0
Example #40
0
def stop(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >> out, "STOPPING", quoted_basedir
    pidfile = os.path.join(basedir, u"twistd.pid")
    if not os.path.exists(pidfile):
        print >> err, "%s does not look like a running node directory (no twistd.pid)" % quoted_basedir
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return COULD_NOT_STOP
    with open(pidfile, "r") as f:
        pid = f.read()

    try:
        pid = int(pid)
    except ValueError:
        # The error message below mimics a Twisted error message, which is
        # displayed when starting a node with an invalid pidfile.
        print >> err, "Pidfile %s contains non-numeric value" % pidfile
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2

    # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
    # process itself to go away. If it hasn't gone away after 20 seconds, warn
    # the user but keep waiting until they give up.
    try:
        os.kill(pid, signal.SIGKILL)
    except OSError, oserr:
        if oserr.errno == 3:
            print oserr.strerror
            # the process didn't exist, so wipe the pid file
            os.remove(pidfile)
            return COULD_NOT_STOP
        else:
            raise
Example #41
0
def leave(options):
    from ConfigParser import SafeConfigParser

    existing_folders = load_magic_folders(options["node-directory"])

    if not existing_folders:
        print("No magic-folders at all", file=options.stderr)
        return 1

    if options["name"] not in existing_folders:
        print("No such magic-folder '{}'".format(options["name"]), file=options.stderr)
        return 1

    privdir = os.path.join(options["node-directory"], u"private")
    db_fname = os.path.join(privdir, u"magicfolder_{}.sqlite".format(options["name"]))

    # delete from YAML file and re-write it
    del existing_folders[options["name"]]
    save_magic_folders(options["node-directory"], existing_folders)

    # delete the database file
    try:
        fileutil.remove(db_fname)
    except Exception as e:
        print("Warning: unable to remove %s due to %s: %s"
            % (quote_local_unicode_path(db_fname), e.__class__.__name__, str(e)), file=options.stderr)

    # if this was the last magic-folder, disable them entirely
    if not existing_folders:
        parser = SafeConfigParser()
        parser.read(os.path.join(options["node-directory"], u"tahoe.cfg"))
        parser.remove_section("magic_folder")
        with open(os.path.join(options["node-directory"], u"tahoe.cfg"), "w") as f:
            parser.write(f)

    return 0
Example #42
0
def find_shares(options):
    """Given a storage index and a list of node directories, emit a list of
    all matching shares to stdout, one per line. For example:

     find-shares.py 44kai1tui348689nrw8fjegc8c ~/testnet/node-*

    gives:

    /home/warner/testnet/node-1/storage/shares/44k/44kai1tui348689nrw8fjegc8c/5
    /home/warner/testnet/node-1/storage/shares/44k/44kai1tui348689nrw8fjegc8c/9
    /home/warner/testnet/node-2/storage/shares/44k/44kai1tui348689nrw8fjegc8c/2
    """
    from allmydata.storage.server import si_a2b, storage_index_to_dir
    from allmydata.util.encodingutil import listdir_unicode, quote_local_unicode_path

    out = options.stdout
    sharedir = storage_index_to_dir(si_a2b(options.si_s))
    for d in options.nodedirs:
        d = os.path.join(d, "storage", "shares", sharedir)
        if os.path.exists(d):
            for shnum in listdir_unicode(d):
                print >>out, quote_local_unicode_path(os.path.join(d, shnum), quotemarks=False)

    return 0
    def test_quote_path(self):
        self.failUnlessReallyEqual(quote_path([u'foo', u'bar']), "'foo/bar'")
        self.failUnlessReallyEqual(quote_path([u'foo', u'bar'], quotemarks=True), "'foo/bar'")
        self.failUnlessReallyEqual(quote_path([u'foo', u'bar'], quotemarks=False), "foo/bar")
        self.failUnlessReallyEqual(quote_path([u'foo', u'\nbar']), '"foo/\\x0abar"')
        self.failUnlessReallyEqual(quote_path([u'foo', u'\nbar'], quotemarks=True), '"foo/\\x0abar"')
        self.failUnlessReallyEqual(quote_path([u'foo', u'\nbar'], quotemarks=False), '"foo/\\x0abar"')

        def win32_other(win32, other):
            return win32 if sys.platform == "win32" else other

        self.failUnlessReallyEqual(quote_local_unicode_path(u"\\\\?\\C:\\foo"),
                                   win32_other("'C:\\foo'", "'\\\\?\\C:\\foo'"))
        self.failUnlessReallyEqual(quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=True),
                                   win32_other("'C:\\foo'", "'\\\\?\\C:\\foo'"))
        self.failUnlessReallyEqual(quote_local_unicode_path(u"\\\\?\\C:\\foo", quotemarks=False),
                                   win32_other("C:\\foo", "\\\\?\\C:\\foo"))
        self.failUnlessReallyEqual(quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar"),
                                   win32_other("'\\\\foo\\bar'", "'\\\\?\\UNC\\foo\\bar'"))
        self.failUnlessReallyEqual(quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar", quotemarks=True),
                                   win32_other("'\\\\foo\\bar'", "'\\\\?\\UNC\\foo\\bar'"))
        self.failUnlessReallyEqual(quote_local_unicode_path(u"\\\\?\\UNC\\foo\\bar", quotemarks=False),
                                   win32_other("\\\\foo\\bar", "\\\\?\\UNC\\foo\\bar"))
Example #44
0
def create_node(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >>err, "The base directory %s is not empty." % quote_local_unicode_path(basedir)
            print >>err, "To avoid clobbering anything, I am going to quit now."
            print >>err, "Please use a different directory, or empty this one."
            defer.returnValue(-1)
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "client")

    # if we're doing magic-wormhole stuff, do it now
    if config['join'] is not None:
        try:
            remote_config = yield _get_config_via_wormhole(config)
        except RuntimeError as e:
            print >>err, str(e)
            defer.returnValue(1)

        # configuration we'll allow the inviter to set
        whitelist = [
            'shares-happy', 'shares-needed', 'shares-total',
            'introducer', 'nickname',
        ]
        sensitive_keys = ['introducer']

        print >>out, "Encoding: {shares-needed} of {shares-total} shares, on at least {shares-happy} servers".format(**remote_config)
        print >>out, "Overriding the following config:"

        for k in whitelist:
            v = remote_config.get(k, None)
            if v is not None:
                # we're faking usually argv-supplied options :/
                if isinstance(v, unicode):
                    v = v.encode(get_io_encoding())
                config[k] = v
                if k not in sensitive_keys:
                    if k not in ['shares-happy', 'shares-total', 'shares-needed']:
                        print >>out, "  {}: {}".format(k, v)
                else:
                    print >>out, "  {}: [sensitive data; see tahoe.cfg]".format(k)

    fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
    with open(os.path.join(basedir, "tahoe.cfg"), "w") as c:
        yield write_node_config(c, config)
        write_client_config(c, config)

    print >>out, "Node created in %s" % quote_local_unicode_path(basedir)
    tahoe_cfg = quote_local_unicode_path(os.path.join(basedir, "tahoe.cfg"))
    if not config.get("introducer", ""):
        print >>out, " Please set [client]introducer.furl= in %s!" % tahoe_cfg
        print >>out, " The node cannot connect to a grid without it."
    if not config.get("nickname", ""):
        print >>out, " Please set [node]nickname= in %s" % tahoe_cfg
    defer.returnValue(0)
Example #45
0
def stop(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print("STOPPING", quoted_basedir, file=out)
    pidfile = get_pidfile(basedir)
    pid = get_pid_from_pidfile(pidfile)
    if pid is None:
        print(
            "%s does not look like a running node directory (no twistd.pid)" %
            quoted_basedir,
            file=err)
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return COULD_NOT_STOP
    elif pid == -1:
        print("%s contains an invalid PID file" % basedir, file=err)
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return COULD_NOT_STOP

    # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
    # process itself to go away. If it hasn't gone away after 20 seconds, warn
    # the user but keep waiting until they give up.
    try:
        os.kill(pid, signal.SIGKILL)
    except OSError as oserr:
        if oserr.errno == 3:
            print(oserr.strerror)
            # the process didn't exist, so wipe the pid file
            os.remove(pidfile)
            return COULD_NOT_STOP
        else:
            raise
    try:
        os.remove(pidfile)
    except EnvironmentError:
        pass
    start = time.time()
    time.sleep(0.1)
    wait = 40
    first_time = True
    while True:
        # poll once per second until we see the process is no longer running
        try:
            os.kill(pid, 0)
        except OSError:
            print("process %d is dead" % pid, file=out)
            return
        wait -= 1
        if wait < 0:
            if first_time:
                print("It looks like pid %d is still running "
                      "after %d seconds" % (pid, (time.time() - start)),
                      file=err)
                print("I will keep watching it until you interrupt me.",
                      file=err)
                wait = 10
                first_time = False
            else:
                print("pid %d still running after %d seconds" % \
                      (pid, (time.time() - start)), file=err)
                wait = 10
        time.sleep(1)
Example #46
0
def create_node(config, out=sys.stdout, err=sys.stderr):
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >>err, "The base directory %s is not empty." % quote_local_unicode_path(basedir)
            print >>err, "To avoid clobbering anything, I am going to quit now."
            print >>err, "Please use a different directory, or empty this one."
            return -1
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "client")

    c = open(os.path.join(basedir, "tahoe.cfg"), "w")

    write_node_config(c, config)

    c.write("[client]\n")
    c.write("# Which services should this client connect to?\n")
    c.write("introducer.furl = %s\n" % config.get("introducer", ""))
    c.write("helper.furl =\n")
    c.write("#key_generator.furl =\n")
    c.write("#stats_gatherer.furl =\n")
    c.write("\n")
    c.write("# What encoding parameters should this client use for uploads?\n")
    c.write("#shares.needed = 3\n")
    c.write("#shares.happy = 7\n")
    c.write("#shares.total = 10\n")
    c.write("\n")

    boolstr = {True:"true", False:"false"}
    c.write("[storage]\n")
    c.write("# Shall this node provide storage service?\n")
    storage_enabled = not config.get("no-storage", None)
    c.write("enabled = %s\n" % boolstr[storage_enabled])
    c.write("#readonly =\n")
    c.write("reserved_space = 1G\n")
    c.write("#expire.enabled =\n")
    c.write("#expire.mode =\n")
    c.write("\n")

    c.write("[helper]\n")
    c.write("# Shall this node run a helper service that clients can use?\n")
    c.write("enabled = false\n")
    c.write("\n")

    c.write("[drop_upload]\n")
    c.write("# Shall this node automatically upload files created or modified in a local directory?\n")
    c.write("enabled = false\n")
    c.write("# To specify the target of uploads, a mutable directory writecap URI must be placed\n"
            "# in 'private/drop_upload_dircap'.\n")
    c.write("local.directory = ~/drop_upload\n")
    c.write("\n")

    c.close()

    from allmydata.util import fileutil
    fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
    print >>out, "Node created in %s" % quote_local_unicode_path(basedir)
    if not config.get("introducer", ""):
        print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
        print >>out, " The node cannot connect to a grid without it."
    if not config.get("nickname", ""):
        print >>out, " Please set [node]nickname= in tahoe.cfg"
    return 0
Example #47
0
def daemonize(config):
    """
    Runs the 'tahoe daemonize' command.

    Sets up the IService instance corresponding to the type of node
    that's starting and uses Twisted's twistd runner to disconnect our
    process from the terminal.
    """
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print("daemonizing in {}".format(quoted_basedir), file=out)
    if not os.path.isdir(basedir):
        print("%s does not look like a directory at all" % quoted_basedir, file=err)
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print("%s is not a recognizable node directory" % quoted_basedir, file=err)
        return 1
    # Now prepare to turn into a twistd process. This os.chdir is the point
    # of no return.
    os.chdir(basedir)
    twistd_args = []
    if (nodetype in (u"client", u"introducer")
        and "--nodaemon" not in config.twistd_args
        and "--syslog" not in config.twistd_args
        and "--logfile" not in config.twistd_args):
        fileutil.make_dirs(os.path.join(basedir, u"logs"))
        twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
    twistd_args.extend(config.twistd_args)
    twistd_args.append("DaemonizeTahoeNode") # point at our DaemonizeTahoeNodePlugin

    twistd_config = MyTwistdConfig()
    try:
        twistd_config.parseOptions(twistd_args)
    except usage.error as ue:
        # these arguments were unsuitable for 'twistd'
        print(config, file=err)
        print("tahoe %s: usage error from twistd: %s\n" % (config.subcommand_name, ue), file=err)
        return 1
    twistd_config.loadedPlugins = {"DaemonizeTahoeNode": DaemonizeTahoeNodePlugin(nodetype, basedir)}

    # handle invalid PID file (twistd might not start otherwise)
    pidfile = get_pidfile(basedir)
    if get_pid_from_pidfile(pidfile) == -1:
        print("found invalid PID file in %s - deleting it" % basedir, file=err)
        os.remove(pidfile)

    # On Unix-like platforms:
    #   Unless --nodaemon was provided, the twistd.runApp() below spawns off a
    #   child process, and the parent calls os._exit(0), so there's no way for
    #   us to get control afterwards, even with 'except SystemExit'. If
    #   application setup fails (e.g. ImportError), runApp() will raise an
    #   exception.
    #
    #   So if we wanted to do anything with the running child, we'd have two
    #   options:
    #
    #    * fork first, and have our child wait for the runApp() child to get
    #      running. (note: just fork(). This is easier than fork+exec, since we
    #      don't have to get PATH and PYTHONPATH set up, since we're not
    #      starting a *different* process, just cloning a new instance of the
    #      current process)
    #    * or have the user run a separate command some time after this one
    #      exits.
    #
    #   For Tahoe, we don't need to do anything with the child, so we can just
    #   let it exit.
    #
    # On Windows:
    #   twistd does not fork; it just runs in the current process whether or not
    #   --nodaemon is specified. (As on Unix, --nodaemon does have the side effect
    #   of causing us to log to stdout/stderr.)

    if "--nodaemon" in twistd_args or sys.platform == "win32":
        verb = "running"
    else:
        verb = "starting"

    print("%s node in %s" % (verb, quoted_basedir), file=out)
    twistd.runApp(twistd_config)
    # we should only reach here if --nodaemon or equivalent was used
    return 0
Example #48
0
    opt_eliot_destination,
    opt_help_eliot_destinations,
    eliot_logging_service,
)

_default_nodedir = get_default_nodedir()

NODEDIR_HELP = ("Specify which Tahoe node directory should be used. The "
                "directory should either contain a full Tahoe node, or a "
                "file named node.url that points to some other Tahoe node. "
                "It should also contain a file named '"
                + os.path.join('private', 'aliases') +
                "' which contains the mapping from alias name to root "
                "dirnode URI.")
if _default_nodedir:
    NODEDIR_HELP += " [default for most commands: " + quote_local_unicode_path(_default_nodedir) + "]"


# XXX all this 'dispatch' stuff needs to be unified + fixed up
_control_node_dispatch = {
    "daemonize": tahoe_daemonize.daemonize,
    "start": tahoe_start.start,
    "run": tahoe_run.run,
    "stop": tahoe_stop.stop,
    "restart": tahoe_restart.restart,
}

process_control_commands = [
    ["daemonize", None, tahoe_daemonize.DaemonizeOptions, "run a node in the background"],
    ["start", None, tahoe_start.StartOptions, "start a node in the background and confirm it started"],
    ["run", None, tahoe_run.RunOptions, "run a node without daemonizing"],
Example #49
0
    opt_eliot_destination,
    opt_help_eliot_destinations,
    eliot_logging_service,
)

_default_nodedir = get_default_nodedir()

NODEDIR_HELP = ("Specify which Tahoe node directory should be used. The "
                "directory should either contain a full Tahoe node, or a "
                "file named node.url that points to some other Tahoe node. "
                "It should also contain a file named '" +
                os.path.join('private', 'aliases') +
                "' which contains the mapping from alias name to root "
                "dirnode URI.")
if _default_nodedir:
    NODEDIR_HELP += " [default for most commands: " + quote_local_unicode_path(
        _default_nodedir) + "]"

# XXX all this 'dispatch' stuff needs to be unified + fixed up
_control_node_dispatch = {
    "daemonize": tahoe_daemonize.daemonize,
    "start": tahoe_start.start,
    "run": tahoe_run.run,
    "stop": tahoe_stop.stop,
    "restart": tahoe_restart.restart,
}

process_control_commands = [
    ["run", None, tahoe_run.RunOptions, "run a node without daemonizing"],
    [
        "daemonize", None, tahoe_daemonize.DaemonizeOptions,
        "(deprecated) run a node in the background"
Example #50
0
 def __init__(self, path, isdir=False):
     self._path = path
     self._quoted_path = quote_local_unicode_path(path)
     self._isdir = isdir
Example #51
0
 def __init__(self, absname):
     quoted = quote_local_unicode_path(absname)
     TahoeError.__init__(self, "source '%s' is neither a file nor a directory, I can't handle it" % quoted)
Example #52
0
def start(config):
    """
    Start a tahoe node (daemonize it and confirm startup)

    We run 'tahoe daemonize' with all the options given to 'tahoe
    start' and then watch the log files for the correct text to appear
    (e.g. "introducer started"). If that doesn't happen within a few
    seconds, an error is printed along with all collected logs.
    """

    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print >>out, "STARTING", quoted_basedir
    if not os.path.isdir(basedir):
        print >>err, "%s does not look like a directory at all" % quoted_basedir
        return 1
    nodetype = identify_node_type(basedir)
    if not nodetype:
        print >>err, "%s is not a recognizable node directory" % quoted_basedir
        return 1

    # "tahoe start" attempts to monitor the logs for successful
    # startup -- but we can't always do that.

    can_monitor_logs = False
    if (nodetype in (u"client", u"introducer")
        and "--nodaemon" not in config.twistd_args
        and "--syslog" not in config.twistd_args
        and "--logfile" not in config.twistd_args):
        can_monitor_logs = True

    if "--help" in config.twistd_args:
        return 0

    if not can_monitor_logs:
        print >>out, "Custom logging options; can't monitor logs for proper startup messages"
        return 1

    # before we spawn tahoe, we check if "the log file" exists or not,
    # and if so remember how big it is -- essentially, we're doing
    # "tail -f" to see what "this" incarnation of "tahoe daemonize"
    # spews forth.
    starting_offset = 0
    log_fname = join(basedir, 'logs', 'twistd.log')
    if exists(log_fname):
        with open(log_fname, 'r') as f:
            f.seek(0, 2)
            starting_offset = f.tell()

    # spawn tahoe. Note that since this daemonizes, it should return
    # "pretty fast" and with a zero return-code, or else something
    # Very Bad has happened.
    try:
        args = [sys.executable] if not getattr(sys, 'frozen', False) else []
        for i, arg in enumerate(sys.argv):
            if arg in ['start', 'restart']:
                args.append('daemonize')
            else:
                args.append(arg)
        subprocess.check_call(args)
    except subprocess.CalledProcessError as e:
        return e.returncode

    # now, we have to determine if tahoe has actually started up
    # successfully or not. so, we start sucking up log files and
    # looking for "the magic string", which depends on the node type.

    magic_string = u'{} running'.format(nodetype)
    with io.open(log_fname, 'r') as f:
        f.seek(starting_offset)

        collected = u''
        overall_start = time.time()
        while time.time() - overall_start < 60:
            this_start = time.time()
            while time.time() - this_start < 5:
                collected += f.read()
                if magic_string in collected:
                    if not config.parent['quiet']:
                        print >>out, "Node has started successfully"
                    return 0
                if 'Traceback ' in collected:
                    print >>err, "Error starting node; see '{}' for more:\n\n{}".format(
                        log_fname,
                        collected,
                    )
                    return 1
                time.sleep(0.1)
            print >>out, "Still waiting up to {}s for node startup".format(
                60 - int(time.time() - overall_start)
            )

        print >>out, "Something has gone wrong starting the node."
        print >>out, "Logs are available in '{}'".format(log_fname)
        print >>out, "Collected for this run:"
        print >>out, collected
        return 1
Example #53
0
 def __init__(self, path, isdir):
     self._path = path
     self._quoted_path = quote_local_unicode_path(path)
     self._isdir = isdir
Example #54
0
def stop(config):
    out = config.stdout
    err = config.stderr
    basedir = config['basedir']
    quoted_basedir = quote_local_unicode_path(basedir)
    print("STOPPING", quoted_basedir, file=out)
    pidfile = get_pidfile(basedir)
    pid = get_pid_from_pidfile(pidfile)
    if pid is None:
        print("%s does not look like a running node directory (no twistd.pid)" % quoted_basedir, file=err)
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2
    elif pid == -1:
        print("%s contains an invalid PID file" % basedir, file=err)
        # we define rc=2 to mean "nothing is running, but it wasn't me who
        # stopped it"
        return 2

    # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
    # process itself to go away. If it hasn't gone away after 20 seconds, warn
    # the user but keep waiting until they give up.
    try:
        os.kill(pid, signal.SIGKILL)
    except OSError as oserr:
        if oserr.errno == 3:
            print(oserr.strerror)
            # the process didn't exist, so wipe the pid file
            os.remove(pidfile)
            return COULD_NOT_STOP
        else:
            raise
    try:
        os.remove(pidfile)
    except EnvironmentError:
        pass
    start = time.time()
    time.sleep(0.1)
    wait = 40
    first_time = True
    while True:
        # poll once per second until we see the process is no longer running
        try:
            os.kill(pid, 0)
        except OSError:
            print("process %d is dead" % pid, file=out)
            return
        wait -= 1
        if wait < 0:
            if first_time:
                print("It looks like pid %d is still running "
                             "after %d seconds" % (pid,
                                                   (time.time() - start)), file=err)
                print("I will keep watching it until you interrupt me.", file=err)
                wait = 10
                first_time = False
            else:
                print("pid %d still running after %d seconds" % \
                      (pid, (time.time() - start)), file=err)
                wait = 10
        time.sleep(1)
Example #55
0
def create_node(config, out=sys.stdout, err=sys.stderr):
    basedir = config['basedir']
    # This should always be called with an absolute Unicode basedir.
    precondition(isinstance(basedir, unicode), basedir)

    if os.path.exists(basedir):
        if listdir_unicode(basedir):
            print >>err, "The base directory %s is not empty." % quote_local_unicode_path(basedir)
            print >>err, "To avoid clobbering anything, I am going to quit now."
            print >>err, "Please use a different directory, or empty this one."
            return -1
        # we're willing to use an empty directory
    else:
        os.mkdir(basedir)
    write_tac(basedir, "client")

    c = open(os.path.join(basedir, "tahoe.cfg"), "w")

    write_node_config(c, config)

    c.write("[client]\n")
    c.write("# Which services should this client connect to?\n")
    c.write("introducer.furl = %s\n" % config.get("introducer", ""))
    c.write("helper.furl =\n")
    c.write("#stats_gatherer.furl =\n")
    c.write("\n")
    c.write("# Encoding parameters this client will use for newly-uploaded files\n")
    c.write("# This can be changed at any time: the encoding is saved in\n")
    c.write("# each filecap, and we can download old files with any encoding\n")
    c.write("# settings\n")
    c.write("#shares.needed = 3\n")
    c.write("#shares.happy = 7\n")
    c.write("#shares.total = 10\n")
    c.write("\n")

    boolstr = {True:"true", False:"false"}
    c.write("[storage]\n")
    c.write("# Shall this node provide storage service?\n")
    storage_enabled = not config.get("no-storage", None)
    c.write("enabled = %s\n" % boolstr[storage_enabled])
    c.write("#readonly =\n")
    c.write("reserved_space = 1G\n")
    c.write("#expire.enabled =\n")
    c.write("#expire.mode =\n")
    c.write("\n")

    c.write("[helper]\n")
    c.write("# Shall this node run a helper service that clients can use?\n")
    c.write("enabled = false\n")
    c.write("\n")

    c.close()

    from allmydata.util import fileutil
    fileutil.make_dirs(os.path.join(basedir, "private"), 0700)
    print >>out, "Node created in %s" % quote_local_unicode_path(basedir)
    if not config.get("introducer", ""):
        print >>out, " Please set [client]introducer.furl= in tahoe.cfg!"
        print >>out, " The node cannot connect to a grid without it."
    if not config.get("nickname", ""):
        print >>out, " Please set [node]nickname= in tahoe.cfg"
    return 0