def copy_to_dir(source, parent_dir, target=None):
    """Copy `source` to `parent_dir`, optionally renaming.

    Args:
        source (str): the source path
        parent_dir (str): the target parent dir. This doesn't have to exist
        target (str, optional): the basename of the target file.  If None,
            use the basename of `source`. Defaults to None.

    Raises:
        SigningServerError: on failure

    """
    target = target or os.path.basename(source)
    target_path = os.path.join(parent_dir, target)
    try:
        parent_dir = os.path.dirname(target_path)
        mkdir(parent_dir)
        if source != target_path:
            log.info("Copying %s to %s" % (source, target_path))
            copyfile(source, target_path)
            return target_path
        else:
            log.info("Not copying %s to itself" % (source))
    except (IOError, OSError):
        traceback.print_exc()
        raise SigningServerError("Can't copy {} to {}!".format(
            source, target_path))
async def get_token(context, output_file, cert_type, signing_formats):
    """Retrieve a token from the signingserver tied to my ip.

    Args:
        context (Context): the signing context
        output_file (str): the path to write the token to.
        cert_type (str): the cert type used to find an appropriate signing server
        signing_formats (list): the signing formats used to find an appropriate
            signing server

    Raises:
        SigningServerError: on failure

    """
    token = None
    data = {
        "slave_ip": context.config["my_ip"],
        "duration": context.config["token_duration_seconds"],
    }
    signing_servers = get_suitable_signing_servers(
        context.signing_servers,
        cert_type,
        [
            fmt
            for fmt in signing_formats if not is_autograph_signing_format(fmt)
        ],
    )
    random.shuffle(signing_servers)
    for s in signing_servers:
        log.info("getting token from %s", s.server)
        url = "https://{}/token".format(s.server)
        auth = aiohttp.BasicAuth(s.user, password=s.password)
        try:
            token = await retry_request(context,
                                        url,
                                        method="post",
                                        data=data,
                                        auth=auth,
                                        return_type="text")
            if token:
                break
        except (
                ScriptWorkerException,
                aiohttp.ClientError,
                asyncio.TimeoutError,
        ) as exc:
            log.warning(
                "Error retrieving token: {}\nTrying the next server.".format(
                    str(exc)))
            continue
    else:
        raise SigningServerError(
            "Cannot retrieve signing token from any signing server.")
    with open(output_file, "w") as fh:
        print(token, file=fh, end="")