Example #1
0
def test_backend_addr_bad_value(url, exc_msg):
    with pytest.raises(ValueError) as exc:
        BackendAddr.from_url(url)
    if isinstance(exc_msg, str):
        assert str(exc.value) == exc_msg
    else:
        assert str(exc.value) in exc_msg
Example #2
0
 def validate(self, string, pos):
     try:
         if len(string) == 0:
             return QValidator.Intermediate, string, pos
         BackendAddr.from_url(string)
         return QValidator.Acceptable, string, pos
     except ValueError:
         return QValidator.Invalid, string, pos
Example #3
0
    def __init__(self, jobs_ctx, config, start_addr):
        super().__init__()
        self.setupUi(self)
        self.jobs_ctx = jobs_ctx
        self.config = config
        self.create_job = None
        self.dialog = None
        self.status = None

        self.device_widget = CreateOrgDeviceInfoWidget()
        self.device_widget.valid_info_entered.connect(self._on_info_valid)
        self.device_widget.invalid_info_entered.connect(self._on_info_invalid)

        self.user_widget = CreateOrgUserInfoWidget()
        self.user_widget.valid_info_entered.connect(self._on_info_valid)
        self.user_widget.invalid_info_entered.connect(self._on_info_invalid)

        self.main_layout.addWidget(self.user_widget)
        self.main_layout.addWidget(self.device_widget)

        self._on_previous_clicked()

        self.button_validate.setEnabled(False)
        self.button_previous.clicked.connect(self._on_previous_clicked)
        self.button_previous.hide()

        self.req_success.connect(self._on_req_success)
        self.req_error.connect(self._on_req_error)

        self.start_addr = start_addr

        if self.start_addr:
            self.user_widget.line_edit_org_name.setText(
                self.start_addr.organization_id)
            self.user_widget.line_edit_org_name.setReadOnly(True)
            self.label_instructions.setText(
                _("TEXT_BOOTSTRAP_ORGANIZATION_INSTRUCTIONS_organization").
                format(organization=self.start_addr.organization_id))
            # Not creating on the default server
            if (self.start_addr.hostname !=
                    config.preferred_org_creation_backend_addr.hostname
                    or self.start_addr.port !=
                    config.preferred_org_creation_backend_addr.port):
                self.user_widget.radio_use_custom.setChecked(True)
                self.user_widget.radio_use_commercial.setDisabled(True)
                # Will not be used, it just makes the display prettier
                backend_addr = BackendAddr(self.start_addr.hostname,
                                           self.start_addr.port,
                                           self.start_addr.use_ssl)
                self.user_widget.line_edit_backend_addr.setText(
                    backend_addr.to_url())
                self.user_widget.line_edit_backend_addr.setDisabled(True)
                self.user_widget.line_edit_backend_addr.setCursorPosition(0)
            else:
                self.user_widget.radio_use_commercial.setChecked(True)
                self.user_widget.radio_use_custom.setDisabled(True)
Example #4
0
def backend_addr(tcp_stream_spy, fixtures_customization, monkeypatch):
    # Depending on tcp_stream_spy fixture prevent from doing real connection
    # attempt (which can be long to resolve) when backend is not running
    use_ssl = fixtures_customization.get("backend_over_ssl", False)
    addr = BackendAddr(hostname="example.com", port=9999, use_ssl=use_ssl)
    if use_ssl:
        # TODO: Trustme & Windows doesn't seem to play well
        # (that and Python < 3.7 & Windows bug https://bugs.python.org/issue35941)
        if sys.platform == "win32":
            pytest.skip("Windows and Trustme are not friends :'(")

        # Create a ssl certificate and overload default ssl context generation
        ca = trustme.CA()
        cert = ca.issue_cert("*.example.com", "example.com")
        vanilla_create_default_context = ssl.create_default_context

        def patched_create_default_context(*args, **kwargs):
            ctx = vanilla_create_default_context(*args, **kwargs)
            ca.configure_trust(ctx)
            cert.configure_cert(
                ctx)  # TODO: only server should load this part ?
            return ctx

        monkeypatch.setattr("ssl.create_default_context",
                            patched_create_default_context)

    return addr
Example #5
0
    async def finalize(self) -> "PkiEnrollmentFinalizedCtx":
        """
        Raises:
            PkiEnrollmentCertificateNotFoundError
            PkiEnrollmentCertificateCryptoError
            PkiEnrollmentCertificateError
            PkiEnrollmentCertificatePinCodeUnavailableError
            PkiEnrollmentLocalPendingCryptoError
        """
        signing_key, private_key = await pki_enrollment_load_local_pending_secret_part(
            config_dir=self.config_dir, enrollment_id=self.enrollment_id)

        # Create the local device
        organization_addr = BackendOrganizationAddr.build(
            backend_addr=BackendAddr(self.addr.hostname, self.addr.port,
                                     self.addr.use_ssl),
            organization_id=self.addr.organization_id,
            root_verify_key=self.accept_payload.root_verify_key,
        )
        new_device = generate_new_device(
            organization_addr=organization_addr,
            device_id=self.accept_payload.device_id,
            profile=self.accept_payload.profile,
            human_handle=self.accept_payload.human_handle,
            device_label=self.accept_payload.device_label,
            signing_key=signing_key,
            private_key=private_key,
        )

        return PkiEnrollmentFinalizedCtx(
            config_dir=self.config_dir,
            enrollment_id=self.enrollment_id,
            new_device=new_device,
            x509_certificate=self.x509_certificate,
        )
Example #6
0
    async def _server_factory(entry_point, addr=None):
        nonlocal count
        count += 1

        if not addr:
            addr = BackendAddr(hostname=f"server-{count}.localhost",
                               port=9999,
                               use_ssl=False)

        async with trio.open_service_nursery() as nursery:

            def connection_factory(*args, **kwargs):
                client_stream, server_stream = trio.testing.memory_stream_pair(
                )
                nursery.start_soon(entry_point, server_stream)
                return client_stream

            tcp_stream_spy.push_hook(addr, connection_factory)
            try:
                yield AppServer(entry_point, addr, connection_factory)
                nursery.cancel_scope.cancel()

            finally:
                # It's important to remove the hook just after having cancelled
                # the nursery. Otherwise another coroutine trying to connect would
                # end up with a `RuntimeError('Nursery is closed to new arrivals',)`
                # given `connection_factory` make use of the now-closed nursery.
                tcp_stream_spy.pop_hook(addr)
Example #7
0
def core_config(tmpdir, backend_addr, unused_tcp_port, fixtures_customization):
    if fixtures_customization.get("fake_preferred_org_creation_backend_addr", False):
        backend_addr = BackendAddr.from_url(f"parsec://127.0.0.1:{unused_tcp_port}")

    tmpdir = Path(tmpdir)
    return CoreConfig(
        config_dir=tmpdir / "config",
        data_base_dir=tmpdir / "data",
        mountpoint_base_dir=tmpdir / "mnt",
        preferred_org_creation_backend_addr=backend_addr,
        gui_language=fixtures_customization.get("gui_language"),
    )
Example #8
0
async def _status_organization(organization_id: OrganizationID,
                               backend_addr: BackendAddr,
                               administration_token: str) -> None:
    url = backend_addr.to_http_domain_url(
        f"/administration/organizations/{organization_id}")

    rep_data = await http_request(
        url=url,
        method="GET",
        headers={"authorization": f"Bearer {administration_token}"})

    cooked_rep_data = organization_config_rep_serializer.loads(rep_data)
    for key, value in cooked_rep_data.items():
        click.echo(f"{key}: {value}")
Example #9
0
def test_backend_organization_addr_good(base_url, expected, verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationAddr.build(backend_addr,
                                         organization_id=org,
                                         root_verify_key=verify_key)
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.root_verify_key == verify_key

    addr2 = BackendOrganizationAddr.from_url(addr.to_url())
    assert addr == addr2
def test_build_addrs():
    backend_addr = BackendAddr.from_url(BackendAddrTestbed.url)
    assert backend_addr.hostname == "parsec.cloud.com"
    assert backend_addr.port == 443
    assert backend_addr.use_ssl is True

    organization_id = OrganizationID("MyOrg")
    root_verify_key = SigningKey.generate().verify_key

    organization_addr = BackendOrganizationAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, root_verify_key=root_verify_key
    )
    assert organization_addr.organization_id == organization_id
    assert organization_addr.root_verify_key == root_verify_key

    organization_bootstrap_addr = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        token="a0000000000000000000000000000001",
    )
    assert organization_bootstrap_addr.token == "a0000000000000000000000000000001"
    assert organization_bootstrap_addr.organization_id == organization_id

    organization_bootstrap_addr2 = BackendOrganizationBootstrapAddr.build(
        backend_addr=backend_addr, organization_id=organization_id, token=None
    )
    assert organization_bootstrap_addr2.organization_id == organization_id
    assert organization_bootstrap_addr2.token == ""

    organization_file_link_addr = BackendOrganizationFileLinkAddr.build(
        organization_addr=organization_addr,
        workspace_id=EntryID.from_hex("2d4ded12-7406-4608-833b-7f57f01156e2"),
        encrypted_path=b"<encrypted_payload>",
    )
    assert organization_file_link_addr.workspace_id == EntryID.from_hex(
        "2d4ded12-7406-4608-833b-7f57f01156e2"
    )
    assert organization_file_link_addr.encrypted_path == b"<encrypted_payload>"

    invitation_addr = BackendInvitationAddr.build(
        backend_addr=backend_addr,
        organization_id=organization_id,
        invitation_type=InvitationType.USER,
        token=InvitationToken.from_hex("a0000000000000000000000000000001"),
    )
    assert invitation_addr.organization_id == organization_id
    assert invitation_addr.token == InvitationToken.from_hex("a0000000000000000000000000000001")
    assert invitation_addr.invitation_type == InvitationType.USER
async def create_organization_req(organization_id: OrganizationID,
                                  backend_addr: BackendAddr,
                                  administration_token: str) -> str:
    url = backend_addr.to_http_domain_url("/administration/organizations")
    data = organization_create_req_serializer.dumps(
        {"organization_id": organization_id})

    rep_data = await http_request(
        url=url,
        method="POST",
        headers={"authorization": f"Bearer {administration_token}"},
        data=data,
    )

    cooked_rep_data = organization_create_rep_serializer.loads(rep_data)
    return cooked_rep_data["bootstrap_token"]
Example #12
0
def backend_addr(async_fixture_backend_addr, unused_tcp_port):
    # Given server port is not known until `running_backend_unconfigured_server`
    # is ready, `backend_addr` should be an asynchronous fixture.
    # However `backend_addr` is a really common fixture and we want to be able
    # to use it event in the non-trio tests (for instance in hypothesis tests).
    # So we cheat by pretending `backend_addr` is a sync fixture and fallback to
    # a default addr value if we are in a non-trio test.
    if iscoroutine(async_fixture_backend_addr):
        # We are in a non-trio test, just close the coroutine and provide
        # an addr which is guaranteed to cause connection error
        async_fixture_backend_addr.close()
        # `use_ssl=False` is useful if this address is later modified by `correct_addr`
        return BackendAddr(hostname="127.0.0.1",
                           port=unused_tcp_port,
                           use_ssl=False)
    else:
        return async_fixture_backend_addr
Example #13
0
async def restart_local_backend(administration_token, backend_port, email_host,
                                db, blockstore):
    pattern = f"parsec.* backend.* run.* -P {backend_port}"
    command = (
        f"{sys.executable} -Wignore -m parsec.cli backend run --log-level=WARNING "
        f"-b {blockstore} --db {db} "
        f"--email-host={email_host} -P {backend_port} "
        f"--spontaneous-organization-bootstrap "
        f"--administration-token {administration_token} --backend-addr parsec://localhost:{backend_port}?no_ssl=true"
    )

    # Trio does not support subprocess in windows yet

    def _windows_target():
        for proc in psutil.process_iter():
            if "python" in proc.name():
                arguments = " ".join(proc.cmdline())
                if re.search(pattern, arguments):
                    proc.kill()
        backend_process = subprocess.Popen(command.split(),
                                           stdout=subprocess.PIPE)
        for data in backend_process.stdout:
            print(data.decode(), end="")
            break
        backend_process.stdout.close()

    # Windows restart
    if sys.platform == "win32":
        await trio.to_thread.run_sync(_windows_target)

    # Linux restart
    else:

        await trio.run_process(["pkill", "-f", pattern], check=False)
        backend_process = await trio.open_process(command.split(),
                                                  stdout=subprocess.PIPE)
        async with backend_process.stdout:
            async for data in backend_process.stdout:
                print(data.decode(), end="")
                break

    # Make sure the backend is actually started
    await trio.sleep(0.2)
    url = f"parsec://localhost:{backend_port}?no_ssl=true"
    return BackendAddr.from_url(url)
Example #14
0
async def _anonymous_cmd(serializer, addr: BackendAddr,
                         organization_id: OrganizationID, **req) -> dict:
    """
    Raises:
        BackendNotAvailable
        BackendProtocolError
    """
    logger.info("Request", cmd=req["cmd"])

    try:
        raw_req = serializer.req_dumps(req)

    except ProtocolError as exc:
        logger.exception("Invalid request data", cmd=req["cmd"], error=exc)
        raise BackendProtocolError("Invalid request data") from exc

    url = addr.to_http_domain_url(f"/anonymous/{organization_id}")
    try:
        raw_rep = await http_request(url=url, method="POST", data=raw_req)
    except OSError as exc:
        logger.debug("Request failed (backend not available)",
                     cmd=req["cmd"],
                     exc_info=exc)
        raise BackendNotAvailable(exc) from exc

    try:
        rep = serializer.rep_loads(raw_rep)

    except ProtocolError as exc:
        logger.exception("Invalid response data", cmd=req["cmd"], error=exc)
        raise BackendProtocolError("Invalid response data") from exc

    if rep["status"] == "invalid_msg_format":
        logger.error("Invalid request data according to backend",
                     cmd=req["cmd"],
                     rep=rep)
        raise BackendProtocolError("Invalid request data according to backend")

    if rep["status"] == "bad_timestamp":
        raise BackendOutOfBallparkError(rep)

    return rep
Example #15
0
def test_backend_organization_bootstrap_addr_good(base_url, expected, verify_key):
    org = OrganizationID("org")
    backend_addr = BackendAddr.from_url(base_url)
    addr = BackendOrganizationBootstrapAddr.build(backend_addr, org, "token-123")
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]
    assert addr.organization_id == org
    assert addr.token == "token-123"

    addr2 = BackendOrganizationBootstrapAddr.from_url(str(addr))
    assert addr == addr2

    org_addr = addr.generate_organization_addr(verify_key)
    assert isinstance(org_addr, BackendOrganizationAddr)
    assert org_addr.root_verify_key == verify_key
    assert org_addr.hostname == addr.hostname
    assert org_addr.port == addr.port
    assert org_addr.use_ssl == addr.use_ssl
    assert org_addr.organization_id == addr.organization_id
Example #16
0
async def restart_local_backend(administration_token, backend_port):
    pattern = f"parsec.* backend.* run.* -P {backend_port}"
    command = (
        f"python -Wignore -m parsec.cli backend run -b MOCKED --db MOCKED "
        f"-P {backend_port} --administration-token {administration_token}")

    # Trio does not support subprocess in windows yet

    def _windows_target():
        for proc in psutil.process_iter():
            if "python" in proc.name():
                arguments = " ".join(proc.cmdline())
                if re.search(pattern, arguments):
                    proc.kill()
        backend_process = subprocess.Popen(command.split(),
                                           stdout=subprocess.PIPE)
        for data in backend_process.stdout:
            print(data.decode(), end="")
            break
        backend_process.stdout.close()

    # Windows restart
    if os.name == "nt" or True:
        await trio.to_thread.run_sync(_windows_target)

    # Linux restart
    else:

        await trio.run_process(["pkill", "-f", pattern], check=False)
        backend_process = await trio.open_process(command.split(),
                                                  stdout=subprocess.PIPE)
        async with backend_process.stdout:
            async for data in backend_process.stdout:
                print(data.decode(), end="")
                break

    # Make sure the backend is actually started
    await trio.sleep(0.2)
    url = f"parsec://localhost:{backend_port}?no_ssl=true"
    return BackendAddr.from_url(url)
Example #17
0
async def cli_with_running_backend_testbed(backend, *devices):
    # Must use real TCP sockets instead of the tcp_stream_spy here, this is required
    # given the cli commands are going to run in a separate thread with they own
    # trio loop. Hence sharing memory channel between trio loops is going to create
    # unexpected errors !
    async with trio.open_service_nursery() as nursery:
        listeners = await nursery.start(
            partial(trio.serve_tcp,
                    backend.handle_client,
                    port=0,
                    host="127.0.0.1"))
        _, port, *_ = listeners[0].socket.getsockname()
        backend_addr = BackendAddr("127.0.0.1", port, use_ssl=False)

        # Now the local device point to an invalid backend address, must fix this
        def _correct_local_device_backend_addr(device):
            organization_addr = BackendOrganizationAddr.build(
                backend_addr,
                organization_id=device.organization_addr.organization_id,
                root_verify_key=device.organization_addr.root_verify_key,
            )
            return LocalDevice(
                organization_addr=organization_addr,
                device_id=device.device_id,
                device_label=device.device_label,
                human_handle=device.human_handle,
                signing_key=device.signing_key,
                private_key=device.private_key,
                profile=device.profile,
                user_manifest_id=device.user_manifest_id,
                user_manifest_key=device.user_manifest_key,
                local_symkey=device.local_symkey,
            )

        yield (backend_addr, ) + tuple(
            _correct_local_device_backend_addr(d) for d in devices)

        nursery.cancel_scope.cancel()
Example #18
0
async def async_fixture_backend_addr(running_backend_port_known,
                                     fixtures_customization):
    port = await running_backend_port_known()
    use_ssl = fixtures_customization.get("backend_over_ssl", False)
    return BackendAddr(hostname="127.0.0.1", port=port, use_ssl=use_ssl)
Example #19
0
def backend_addr(tcp_stream_spy):
    # Depending on tcp_stream_spy fixture prevent from doing real connection
    # attempt (which can be long to resolve) when backend is not running
    return BackendAddr(hostname="example.com", port=9999, use_ssl=False)
Example #20
0
 def backend_addr(self):
     return (BackendAddr.from_url(self.line_edit_backend_addr.text(),
                                  allow_http_redirection=True)
             if self.radio_use_custom.isChecked() else None)
Example #21
0
def test_backend_addr_bad_value(url, exc_msg):
    with pytest.raises(ValueError) as exc:
        BackendAddr.from_url(url)
    assert str(exc.value) == exc_msg
 def backend_addr(self):
     return (BackendAddr.from_url(self.line_edit_backend_addr.text())
             if self.check_use_custom_backend.isChecked() else None)
Example #23
0
def config_factory(
    config_dir: Path = None,
    data_base_dir: Path = None,
    cache_base_dir: Path = None,
    mountpoint_base_dir: Path = None,
    prevent_sync_pattern_path: Optional[Path] = None,
    mountpoint_enabled: bool = False,
    disabled_workspaces: FrozenSet[EntryID] = frozenset(),
    backend_max_cooldown: int = 30,
    backend_connection_keepalive: Optional[int] = 29,
    backend_max_connections: int = 4,
    telemetry_enabled: bool = True,
    debug: bool = False,
    gui_last_device: str = None,
    gui_tray_enabled: bool = True,
    gui_language: str = None,
    gui_first_launch: bool = True,
    gui_last_version: str = None,
    gui_check_version_at_startup: bool = True,
    gui_check_version_allow_pre_release: bool = False,
    gui_workspace_color: bool = False,
    gui_allow_multiple_instances: bool = False,
    preferred_org_creation_backend_addr: Optional[BackendAddr] = None,
    gui_show_confined: bool = False,
    gui_geometry: bytes = None,
    environ: dict = {},
    **_,
) -> CoreConfig:

    # The environment variable we always be used first, and if it is not present,
    # we'll use the value from the configuration file.
    backend_addr_env = environ.get("PREFERRED_ORG_CREATION_BACKEND_ADDR")
    if backend_addr_env:
        preferred_org_creation_backend_addr = BackendAddr.from_url(
            backend_addr_env)
    if not preferred_org_creation_backend_addr:
        preferred_org_creation_backend_addr = BackendAddr.from_url(
            "parsec://localhost:6777?no_ssl=true")

    data_base_dir = data_base_dir or get_default_data_base_dir(environ)
    core_config = CoreConfig(
        config_dir=config_dir or get_default_config_dir(environ),
        data_base_dir=data_base_dir,
        cache_base_dir=cache_base_dir or get_default_cache_base_dir(environ),
        mountpoint_base_dir=get_default_mountpoint_base_dir(environ),
        prevent_sync_pattern_path=prevent_sync_pattern_path,
        mountpoint_enabled=mountpoint_enabled,
        disabled_workspaces=disabled_workspaces,
        backend_max_cooldown=backend_max_cooldown,
        backend_connection_keepalive=backend_connection_keepalive,
        backend_max_connections=backend_max_connections,
        telemetry_enabled=telemetry_enabled,
        debug=debug,
        sentry_url=environ.get("SENTRY_URL") or None,
        gui_last_device=gui_last_device,
        gui_tray_enabled=gui_tray_enabled,
        gui_language=gui_language,
        gui_first_launch=gui_first_launch,
        gui_last_version=gui_last_version,
        gui_check_version_at_startup=gui_check_version_at_startup,
        gui_check_version_allow_pre_release=gui_check_version_allow_pre_release,
        gui_workspace_color=gui_workspace_color,
        gui_allow_multiple_instances=gui_allow_multiple_instances,
        preferred_org_creation_backend_addr=preferred_org_creation_backend_addr,
        gui_show_confined=gui_show_confined,
        gui_geometry=gui_geometry,
        ipc_socket_file=data_base_dir / "parsec-cloud.lock",
        ipc_win32_mutex_name="parsec-cloud",
    )

    # Make sure the directories exist on the system
    core_config.config_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
    core_config.data_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
    core_config.cache_base_dir.mkdir(mode=0o700, parents=True, exist_ok=True)

    # Mountpoint base directory is not used on windows
    if os.name != "nt":
        core_config.mountpoint_base_dir.mkdir(mode=0o700,
                                              parents=True,
                                              exist_ok=True)

    return core_config
Example #24
0
def load_config(config_dir: Path, **extra_config) -> CoreConfig:

    config_file = config_dir / "config.json"
    try:
        raw_conf = config_file.read_text()
        data_conf = json.loads(raw_conf)

    except OSError:
        # Config file not created yet, fallback to default
        data_conf = {}

    except (ValueError, json.JSONDecodeError) as exc:
        # Config file broken, fallback to default
        logger.warning(f"Ignoring invalid config in {config_file} ({exc})")
        data_conf = {}

    try:
        data_conf["data_base_dir"] = Path(data_conf["data_base_dir"])
    except (KeyError, ValueError):
        pass

    try:
        data_conf["cache_base_dir"] = Path(data_conf["cache_base_dir"])
    except (KeyError, ValueError):
        pass

    try:
        data_conf["prevent_sync_pattern_path"] = Path(
            data_conf["prevent_sync_pattern_path"])
    except (KeyError, ValueError):
        pass

    try:
        data_conf["disabled_workspaces"] = frozenset(
            map(EntryID, data_conf["disabled_workspaces"]))
    except (KeyError, ValueError):
        pass

    try:
        data_conf[
            "preferred_org_creation_backend_addr"] = BackendAddr.from_url(
                data_conf["preferred_org_creation_backend_addr"])
    except KeyError:
        pass
    except ValueError as exc:
        logger.warning(
            f"Invalid value for `preferred_org_creation_backend_addr` ({exc})")
        data_conf["preferred_org_creation_backend_addr"] = None

    try:
        data_conf["gui_geometry"] = base64.b64decode(
            data_conf["gui_geometry"].encode("ascii"))
    except (AttributeError, KeyError, UnicodeEncodeError, binascii.Error):
        data_conf["gui_geometry"] = None

    # Work around versionning issue with parsec releases:
    # - v1.12.0, v1.11.4, v1.11.3, v1.11.2, v1.11.1, v1.11.0 and v1.10.0
    # A `v` has been incorrectly added to `parsec.__version__`, potentially
    # affecting the `gui_last_version` entry in the configuration file.
    if data_conf.get("gui_last_version"):
        data_conf["gui_last_version"] = data_conf["gui_last_version"].lstrip(
            "v")

    return config_factory(config_dir=config_dir,
                          **data_conf,
                          **extra_config,
                          environ=os.environ)
Example #25
0
def test_backend_addr_good(url, expected):
    addr = BackendAddr.from_url(url)
    assert addr.hostname == "foo"
    assert addr.port == expected["port"]
    assert addr.use_ssl == expected["ssl"]