示例#1
0
    def test_static_servers(self):
        broker = make_broker()

        key_s = b'v0-1234-1'
        servers_yaml = """\
storage:
  v0-1234-1:
    ann:
      anonymous-storage-FURL: {furl}
      permutation-seed-base32: aaaaaaaaaaaaaaaaaaaaaaaa
""".format(furl=SOME_FURL)
        servers = yamlutil.safe_load(servers_yaml)
        permseed = base32.a2b(b"aaaaaaaaaaaaaaaaaaaaaaaa")
        broker.set_static_servers(servers["storage"])
        self.failUnlessEqual(len(broker._static_server_ids), 1)
        s = broker.servers[key_s]
        self.failUnlessEqual(s.announcement,
                             servers["storage"]["v0-1234-1"]["ann"])
        self.failUnlessEqual(s.get_serverid(), key_s)
        self.assertEqual(s.get_permutation_seed(), permseed)

        # if the Introducer announces the same thing, we're supposed to
        # ignore it

        ann2 = {
            "service-name": "storage",
            "anonymous-storage-FURL": "pb://{}@nowhere/fake2".format(str(base32.b2a(b"1"), "utf-8")),
            "permutation-seed-base32": "bbbbbbbbbbbbbbbbbbbbbbbb",
        }
        broker._got_announcement(key_s, ann2)
        s2 = broker.servers[key_s]
        self.assertIdentical(s2, s)
        self.assertEqual(s2.get_permutation_seed(), permseed)
    def test_static_servers(self):
        broker = StorageFarmBroker(True, lambda h: Mock())

        key_s = 'v0-1234-1'
        servers_yaml = """\
storage:
  v0-1234-1:
    ann:
      anonymous-storage-FURL: pb://ge@nowhere/fake
      permutation-seed-base32: aaaaaaaaaaaaaaaaaaaaaaaa
"""
        servers = yamlutil.safe_load(servers_yaml)
        permseed = base32.a2b("aaaaaaaaaaaaaaaaaaaaaaaa")
        broker.set_static_servers(servers["storage"])
        self.failUnlessEqual(len(broker._static_server_ids), 1)
        s = broker.servers[key_s]
        self.failUnlessEqual(s.announcement,
                             servers["storage"]["v0-1234-1"]["ann"])
        self.failUnlessEqual(s.get_serverid(), key_s)
        self.assertEqual(s.get_permutation_seed(), permseed)

        # if the Introducer announces the same thing, we're supposed to
        # ignore it

        ann2 = {
            "service-name": "storage",
            "anonymous-storage-FURL": "pb://{}@nowhere/fake2".format(base32.b2a(str(1))),
            "permutation-seed-base32": "bbbbbbbbbbbbbbbbbbbbbbbb",
        }
        broker._got_announcement(key_s, ann2)
        s2 = broker.servers[key_s]
        self.assertIdentical(s2, s)
        self.assertEqual(s2.get_permutation_seed(), permseed)
示例#3
0
    def init_introducer_clients(self):
        self.introducer_clients = []
        self.introducer_furls = []

        introducers_yaml_filename = os.path.join(self.basedir, "private", "introducers.yaml")
        introducers_filepath = FilePath(introducers_yaml_filename)

        try:
            with introducers_filepath.open() as f:
                introducers_yaml = yamlutil.safe_load(f)
                introducers = introducers_yaml.get("introducers", {})
                log.msg("found %d introducers in private/introducers.yaml" %
                        len(introducers))
        except EnvironmentError:
            introducers = {}

        if "default" in introducers.keys():
            raise ValueError("'default' introducer furl cannot be specified in introducers.yaml; please fix impossible configuration.")

        # read furl from tahoe.cfg
        tahoe_cfg_introducer_furl = self.get_config("client", "introducer.furl", None)
        if tahoe_cfg_introducer_furl:
            introducers[u'default'] = {'furl':tahoe_cfg_introducer_furl}

        for petname, introducer in introducers.items():
            introducer_cache_filepath = FilePath(os.path.join(self.basedir, "private", "introducer_{}_cache.yaml".format(petname)))
            ic = IntroducerClient(self.tub, introducer['furl'],
                                  self.nickname,
                                  str(allmydata.__full_version__),
                                  str(self.OLDEST_SUPPORTED_VERSION),
                                  self.get_app_versions(), self._sequencer, introducer_cache_filepath)
            self.introducer_clients.append(ic)
            self.introducer_furls.append(introducer['furl'])
            ic.setServiceParent(self)
示例#4
0
def create_introducer_clients(config, main_tub):
    """
    Read, validate and parse any 'introducers.yaml' configuration.

    :returns: a list of IntroducerClient instances
    """
    # we return this list
    introducer_clients = []

    introducers_yaml_filename = config.get_private_path("introducers.yaml")
    introducers_filepath = FilePath(introducers_yaml_filename)

    try:
        with introducers_filepath.open() as f:
            introducers_yaml = yamlutil.safe_load(f)
            if introducers_yaml is None:
                raise EnvironmentError(
                    EPERM,
                    "Can't read '{}'".format(introducers_yaml_filename),
                    introducers_yaml_filename,
                )
            introducers = introducers_yaml.get("introducers", {})
            log.msg("found {} introducers in private/introducers.yaml".format(
                len(introducers), ))
    except EnvironmentError as e:
        if e.errno != ENOENT:
            raise
        introducers = {}

    if "default" in introducers.keys():
        raise ValueError(
            "'default' introducer furl cannot be specified in introducers.yaml;"
            " please fix impossible configuration.")

    # read furl from tahoe.cfg
    tahoe_cfg_introducer_furl = config.get_config("client", "introducer.furl",
                                                  None)
    if tahoe_cfg_introducer_furl == "None":
        raise ValueError("tahoe.cfg has invalid 'introducer.furl = None':"
                         " to disable it, use 'introducer.furl ='"
                         " or omit the key entirely")
    if tahoe_cfg_introducer_furl:
        introducers[u'default'] = {'furl': tahoe_cfg_introducer_furl}

    for petname, introducer in introducers.items():
        introducer_cache_filepath = FilePath(
            config.get_private_path(
                "introducer_{}_cache.yaml".format(petname)))
        ic = IntroducerClient(
            main_tub,
            introducer['furl'].encode("ascii"),
            config.nickname,
            str(allmydata.__full_version__),
            str(_Client.OLDEST_SUPPORTED_VERSION),
            node.get_app_versions(),
            partial(_sequencer, config),
            introducer_cache_filepath,
        )
        introducer_clients.append(ic)
    return introducer_clients
示例#5
0
 def test_convert(self):
     """
     Unicode and (ASCII) native strings get roundtripped to Unicode strings.
     """
     data = yaml.safe_dump(
         [six.ensure_str("str"), u"unicode", u"\u1234nicode"])
     back = yamlutil.safe_load(data)
     self.assertIsInstance(back[0], str)
     self.assertIsInstance(back[1], str)
     self.assertIsInstance(back[2], str)
示例#6
0
 def load_connections(self):
     """
     Load the connections.yaml file if it exists, otherwise
     create a default configuration.
     """
     fn = os.path.join(self.basedir, "private", "connections.yaml")
     connections_filepath = FilePath(fn)
     try:
         with connections_filepath.open() as f:
             self.connections_config = yamlutil.safe_load(f)
     except EnvironmentError:
         self.connections_config = { 'servers' : {} }
         content = yamlutil.safe_dump(self.connections_config)
         connections_filepath.setContent(content)
示例#7
0
 def load_connections(self):
     """
     Load the connections.yaml file if it exists, otherwise
     create a default configuration.
     """
     fn = os.path.join(self.basedir, "private", "connections.yaml")
     connections_filepath = FilePath(fn)
     try:
         with connections_filepath.open() as f:
             self.connections_config = yamlutil.safe_load(f)
     except EnvironmentError:
         self.connections_config = { 'servers' : {} }
         content = yamlutil.safe_dump(self.connections_config)
         connections_filepath.setContent(content)
示例#8
0
 def load_static_servers(self):
     """
     Load the servers.yaml file if it exists, and provide the static
     server data to the StorageFarmBroker.
     """
     fn = os.path.join(self.basedir, "private", "servers.yaml")
     servers_filepath = FilePath(fn)
     try:
         with servers_filepath.open() as f:
             servers_yaml = yamlutil.safe_load(f)
         static_servers = servers_yaml.get("storage", {})
         log.msg("found %d static servers in private/servers.yaml" %
                 len(static_servers))
         self.storage_broker.set_static_servers(static_servers)
     except EnvironmentError:
         pass
示例#9
0
 def load_static_servers(self):
     """
     Load the servers.yaml file if it exists, and provide the static
     server data to the StorageFarmBroker.
     """
     fn = self.config.get_private_path("servers.yaml")
     servers_filepath = FilePath(fn)
     try:
         with servers_filepath.open() as f:
             servers_yaml = yamlutil.safe_load(f)
         static_servers = servers_yaml.get("storage", {})
         log.msg("found %d static servers in private/servers.yaml" %
                 len(static_servers))
         self.storage_broker.set_static_servers(static_servers)
     except EnvironmentError:
         pass
示例#10
0
 def _load_announcements(self):
     try:
         with self._cache_filepath.open() as f:
             servers = yamlutil.safe_load(f)
     except EnvironmentError:
         return # no cache file
     if not isinstance(servers, list):
         log.err(InvalidCacheError("not a list"), level=log.WEIRD)
         return
     self.log("Using server data from cache", level=log.UNUSUAL)
     for server_params in servers:
         if not isinstance(server_params, dict):
             log.err(InvalidCacheError("not a dict: %r" % (server_params,)),
                     level=log.WEIRD)
             continue
         self._deliver_announcements(server_params['key_s'],
                                     server_params['ann'])
示例#11
0
    def init_introducer_clients(self):
        self.introducer_clients = []
        self.introducer_furls = []

        introducers_yaml_filename = os.path.join(self.basedir, "private",
                                                 "introducers.yaml")
        introducers_filepath = FilePath(introducers_yaml_filename)

        try:
            with introducers_filepath.open() as f:
                introducers_yaml = yamlutil.safe_load(f)
                introducers = introducers_yaml.get("introducers", {})
                log.msg("found %d introducers in private/introducers.yaml" %
                        len(introducers))
        except EnvironmentError:
            introducers = {}

        if "default" in introducers.keys():
            raise ValueError(
                "'default' introducer furl cannot be specified in introducers.yaml; please fix impossible configuration."
            )

        # read furl from tahoe.cfg
        tahoe_cfg_introducer_furl = self.get_config("client",
                                                    "introducer.furl", None)
        if tahoe_cfg_introducer_furl == "None":
            raise ValueError("tahoe.cfg has invalid 'introducer.furl = None':"
                             " to disable it, use 'introducer.furl ='"
                             " or omit the key entirely")
        if tahoe_cfg_introducer_furl:
            introducers[u'default'] = {'furl': tahoe_cfg_introducer_furl}

        for petname, introducer in introducers.items():
            introducer_cache_filepath = FilePath(
                os.path.join(self.basedir, "private",
                             "introducer_{}_cache.yaml".format(petname)))
            ic = IntroducerClient(self.tub, introducer['furl'].encode("ascii"),
                                  self.nickname,
                                  str(allmydata.__full_version__),
                                  str(self.OLDEST_SUPPORTED_VERSION),
                                  self.get_app_versions(), self._sequencer,
                                  introducer_cache_filepath)
            self.introducer_clients.append(ic)
            self.introducer_furls.append(introducer['furl'])
            ic.setServiceParent(self)
示例#12
0
 def _load_announcements(self):
     try:
         with self._cache_filepath.open() as f:
             servers = yamlutil.safe_load(f)
     except EnvironmentError:
         return # no cache file
     if not isinstance(servers, list):
         log.err(InvalidCacheError("not a list"), level=log.WEIRD)
         return
     self.log("Using server data from cache", level=log.UNUSUAL)
     for server_params in servers:
         if not isinstance(server_params, dict):
             log.err(InvalidCacheError("not a dict: %r" % (server_params,)),
                     level=log.WEIRD)
             continue
         # everything coming from yamlutil.safe_load is unicode
         key_s = server_params['key_s'].encode("ascii")
         self._deliver_announcements(key_s, server_params['ann'])
示例#13
0
def create_introducer_clients(config, main_tub):
    """
    Read, validate and parse any 'introducers.yaml' configuration.

    :returns: a list of IntroducerClient instances
    """
    # we return this list
    introducer_clients = []

    introducers_yaml_filename = config.get_private_path("introducers.yaml")
    introducers_filepath = FilePath(introducers_yaml_filename)

    try:
        with introducers_filepath.open() as f:
            introducers_yaml = yamlutil.safe_load(f)
            if introducers_yaml is None:
                raise EnvironmentError(
                    EPERM,
                    "Can't read '{}'".format(introducers_yaml_filename),
                    introducers_yaml_filename,
                )
            introducers = introducers_yaml.get("introducers", {})
            log.msg(
                "found {} introducers in private/introducers.yaml".format(
                    len(introducers),
                )
            )
    except EnvironmentError as e:
        if e.errno != ENOENT:
            raise
        introducers = {}

    if "default" in introducers.keys():
        raise ValueError(
            "'default' introducer furl cannot be specified in introducers.yaml;"
            " please fix impossible configuration."
        )

    # read furl from tahoe.cfg
    tahoe_cfg_introducer_furl = config.get_config("client", "introducer.furl", None)
    if tahoe_cfg_introducer_furl == "None":
        raise ValueError(
            "tahoe.cfg has invalid 'introducer.furl = None':"
            " to disable it, use 'introducer.furl ='"
            " or omit the key entirely"
        )
    if tahoe_cfg_introducer_furl:
        introducers[u'default'] = {'furl':tahoe_cfg_introducer_furl}

    for petname, introducer in introducers.items():
        introducer_cache_filepath = FilePath(config.get_private_path("introducer_{}_cache.yaml".format(petname)))
        ic = IntroducerClient(
            main_tub,
            introducer['furl'].encode("ascii"),
            config.nickname,
            str(allmydata.__full_version__),
            str(_Client.OLDEST_SUPPORTED_VERSION),
            node.get_app_versions(),
            partial(_sequencer, config),
            introducer_cache_filepath,
        )
        introducer_clients.append(ic)
    return introducer_clients
 def _load_cache(self, cache_filepath):
     with cache_filepath.open() as f:
         return yamlutil.safe_load(f)
示例#15
0
 def test_convert(self):
     data = yaml.safe_dump(["str", u"unicode", u"\u1234nicode"])
     back = yamlutil.safe_load(data)
     self.assertIsInstance(back[0], str)
     self.assertIsInstance(back[1], str)
     self.assertIsInstance(back[2], str)
示例#16
0
 def _load_cache(self, cache_filepath):
     with cache_filepath.open() as f:
         return yamlutil.safe_load(f)
示例#17
0
def load_magic_folders(node_directory):
    """
    Loads existing magic-folder configuration and returns it as a dict
    mapping name -> dict of config. This will NOT upgrade from
    old-style to new-style config (but WILL read old-style config and
    return in the same way as if it was new-style).

    :returns: dict mapping magic-folder-name to its config (also a dict)
    """
    yaml_fname = os.path.join(node_directory, u"private", u"magic_folders.yaml")
    folders = dict()

    config_fname = os.path.join(node_directory, "tahoe.cfg")
    config = configutil.get_config(config_fname)

    if not os.path.exists(yaml_fname):
        # there will still be a magic_folder section in a "new"
        # config, but it won't have local.directory nor poll_interval
        # in it.
        if config.has_option("magic_folder", "local.directory"):
            up_fname = os.path.join(node_directory, "private", "magic_folder_dircap")
            coll_fname = os.path.join(node_directory, "private", "collective_dircap")
            directory = config.get("magic_folder", "local.directory").decode('utf8')
            try:
                interval = int(config.get("magic_folder", "poll_interval"))
            except ConfigParser.NoOptionError:
                interval = 60
            dir_fp = to_filepath(directory)

            if not dir_fp.exists():
                raise Exception(
                    "The '[magic_folder] local.directory' parameter is {} "
                    "but there is no directory at that location.".format(
                        quote_local_unicode_path(directory),
                    )
                )
            if not dir_fp.isdir():
                raise Exception(
                    "The '[magic_folder] local.directory' parameter is {} "
                    "but the thing at that location is not a directory.".format(
                        quote_local_unicode_path(directory)
                    )
                )

            folders[u"default"] = {
                u"directory": directory,
                u"upload_dircap": fileutil.read(up_fname),
                u"collective_dircap": fileutil.read(coll_fname),
                u"poll_interval": interval,
            }
        else:
            # without any YAML file AND no local.directory option it's
            # an error if magic-folder is "enabled" because we don't
            # actually have enough config for any magic-folders at all
            if config.has_section("magic_folder") \
               and config.getboolean("magic_folder", "enabled") \
               and not folders:
                raise Exception(
                    "[magic_folder] is enabled but has no YAML file and no "
                    "'local.directory' option."
                )

    elif os.path.exists(yaml_fname):  # yaml config-file exists
        if config.has_option("magic_folder", "local.directory"):
            raise Exception(
                "magic-folder config has both old-style configuration"
                " and new-style configuration; please remove the "
                "'local.directory' key from tahoe.cfg or remove "
                "'magic_folders.yaml' from {}".format(node_directory)
            )
        with open(yaml_fname, "r") as f:
            magic_folders = yamlutil.safe_load(f.read())
            if not isinstance(magic_folders, dict):
                raise Exception(
                    "'{}' should contain a dict".format(yaml_fname)
                )

            folders = magic_folders['magic-folders']
            if not isinstance(folders, dict):
                raise Exception(
                    "'magic-folders' in '{}' should be a dict".format(yaml_fname)
                )

    # check configuration
    for (name, mf_config) in folders.items():
        if not isinstance(mf_config, dict):
            raise Exception(
                "Each item in '{}' must itself be a dict".format(yaml_fname)
            )
        for k in ['collective_dircap', 'upload_dircap', 'directory', 'poll_interval']:
            if k not in mf_config:
                raise Exception(
                    "Config for magic folder '{}' is missing '{}'".format(
                        name, k
                    )
                )
        for k in ['collective_dircap', 'upload_dircap']:
            if isinstance(mf_config[k], unicode):
                mf_config[k] = mf_config[k].encode('ascii')

    return folders
示例#18
0
    def get_introducer_configuration(self):
        """
        Get configuration for introducers.

        :return {unicode: (unicode, FilePath)}: A mapping from introducer
            petname to a tuple of the introducer's fURL and local cache path.
        """
        introducers_yaml_filename = self.get_private_path("introducers.yaml")
        introducers_filepath = FilePath(introducers_yaml_filename)

        def get_cache_filepath(petname):
            return FilePath(
                self.get_private_path(
                    "introducer_{}_cache.yaml".format(petname)), )

        try:
            with introducers_filepath.open() as f:
                introducers_yaml = safe_load(f)
                if introducers_yaml is None:
                    raise EnvironmentError(
                        EPERM,
                        "Can't read '{}'".format(introducers_yaml_filename),
                        introducers_yaml_filename,
                    )
                introducers = {
                    petname: config["furl"]
                    for petname, config in introducers_yaml.get(
                        "introducers", {}).items()
                }
                non_strs = list(k for k in introducers.keys()
                                if not isinstance(k, str))
                if non_strs:
                    raise TypeError(
                        "Introducer petnames {!r} should have been str".format(
                            non_strs, ), )
                non_strs = list(v for v in introducers.values()
                                if not isinstance(v, str))
                if non_strs:
                    raise TypeError(
                        "Introducer fURLs {!r} should have been str".format(
                            non_strs, ), )
                log.msg("found {} introducers in {!r}".format(
                    len(introducers),
                    introducers_yaml_filename,
                ))
        except EnvironmentError as e:
            if e.errno != ENOENT:
                raise
            introducers = {}

        # supported the deprecated [client]introducer.furl item in tahoe.cfg
        tahoe_cfg_introducer_furl = self.get_config("client",
                                                    "introducer.furl", None)
        if tahoe_cfg_introducer_furl == "None":
            raise ValueError("tahoe.cfg has invalid 'introducer.furl = None':"
                             " to disable it omit the key entirely")
        if tahoe_cfg_introducer_furl:
            warn(
                "tahoe.cfg [client]introducer.furl is deprecated; "
                "use private/introducers.yaml instead.",
                category=DeprecationWarning,
                stacklevel=-1,
            )
            if "default" in introducers:
                raise ValueError(
                    "'default' introducer furl cannot be specified in tahoe.cfg and introducers.yaml;"
                    " please fix impossible configuration.")
            introducers['default'] = tahoe_cfg_introducer_furl

        return {
            petname: (furl, get_cache_filepath(petname))
            for (petname, furl) in introducers.items()
        }
示例#19
0
 def test_convert(self):
     data = yaml.safe_dump(["str", u"unicode", u"\u1234nicode"])
     back = yamlutil.safe_load(data)
     self.failUnlessEqual(type(back[0]), unicode)
     self.failUnlessEqual(type(back[1]), unicode)
     self.failUnlessEqual(type(back[2]), unicode)