示例#1
0
def setup_pubpublica_access(c, ctx):
    user = ctx.get("USER")
    group = ctx.get("GROUP")

    with Guard("· creating user and group..."):
        if user:
            if not system.create_user(c, user, sudo=True):
                raise Exception(f"failed to create user '{user}'")

        if group:
            if not system.create_group(c, group, sudo=True):
                raise Exception(f"failed to create group '{group}")

            if not system.group_add_user(c, group, user, sudo=True):
                raise Exception(
                    f"failed to add user '{user} to group '{group}")

    with Guard("· changing permissions..."):
        deploy_path = ctx.get("DEPLOY_PATH")
        if user:
            if not access.change_owner(
                    c, deploy_path, user, recursive=True, sudo=True):
                raise Exception(f"failed to change owner of deployment")

        if group:
            if not access.change_group(
                    c, deploy_path, group, recursive=True, sudo=True):
                raise Exception(f"failed to change group of deployment")
示例#2
0
def check_local_git_repo(c, ctx):
    with Guard("· checking local git repo..."):
        root = ctx.get("LOCAL_APP_PATH")
        dirty = git.is_dirty(c, root)

        if dirty is None:
            raise GuardWarning(f"{root} is not a git repository")

        if dirty:
            raise GuardWarning("local git repository is dirty")
示例#3
0
def setup_pubpublica_virtualenv(c, ctx):
    deploy_path = ctx.get("DEPLOY_PATH")

    venv_dir = os.path.join(deploy_path, "venv")

    with Guard("· creating virtual environment..."):
        create_venv = f"python3.8 -m venv {venv_dir}"
        ret = c.sudo(create_venv, hide=True, warn=True)
        if not ret.ok:
            raise Exception(f"failed creating virtual environment: {ret}")

    with Guard("· updating virtual environment..."):
        pip_file = os.path.join(venv_dir, "bin", "pip3.8")
        requirements_file = os.path.join(deploy_path, "requirements.txt")
        pip_install = f"{pip_file} install -r {requirements_file}"

        ret = c.sudo(pip_install, hide=True, warn=True)
        if not ret.ok:
            raise Exception(f"failed to update the virtual environment: {ret}")
示例#4
0
def setup_nginx(c, ctx):
    # TODO: copy over nginx settings
    print("setting up nginx")

    with Guard("· building config files..."):
        if not (cfg := ctx.get("NGINX") or {}):
            pass

        config_path = ctx.get("LOCAL_CONFIG_PATH")
        nginx_template = os.path.join(config_path, ".nginx")
示例#5
0
def check_deployment(c, ctx):
    with Guard("· checking deployment..."):
        app_path = ctx.get("APP_PATH")
        id_file = ctx.get("DEPLOYED_ID_FILE")
        deployment_file = os.path.join(app_path, id_file)
        id = fs.read_file(c, deployment_file)

        if not id:
            raise GuardWarning("unable to find deployed id")

        ctx.update({"DEPLOYED_ARTIFACT_ID": id})
示例#6
0
def check_dependencies(c, ctx):
    with Guard("· checking dependencies..."):
        missing = []
        deps = ctx.get("DEPENDENCIES") or []
        for dep in deps:
            if not apt.is_installed(c, dep):
                missing.append(dep)

        if missing:
            raise Exception(
                f"the following dependencies are not installed: {missing}")
示例#7
0
def unpack_project(c, ctx):
    with Guard("· unpacking..."):
        deploy_path = ctx.get("DEPLOY_PATH")
        artifact = ctx.get("ARTIFACT_FILE")
        artifact_path = os.path.join(deploy_path, artifact)

        cmd = f"tar -C {deploy_path} -xzf {artifact_path}"
        unpack = c.sudo(cmd, hide=True, warn=True)

        if not unpack.ok:
            raise Exception(f"failed to unpack project: {unpack.stderr}")

        if not fs.remove(c, artifact_path, sudo=True):
            raise GuardWarning("failed to remove artifact after unpacking")
示例#8
0
def check_versions(c, ctx):
    with Guard("· checking versions..."):
        production_path = ctx.get("PRODUCTION_PATH")
        remote_ver_file = os.path.join(production_path, "__version__.py")
        v_remote = fs.read_file(c, remote_ver_file)

        if not v_remote:
            raise GuardWarning("unable to retrieve deployed version")

        ctx.update({"REMOTE_VERSION": v_remote})

        v_local = ctx.get("LOCAL_VERSION")
        if not util.version_newer(v_local, v_remote):
            raise GuardWarning(
                f"{v_local} is older or equal to deployed {v_remote}")
示例#9
0
def pack_project(c, ctx):
    def _tar_filter(info):
        if "__pycache__" in info.name:
            return None
        return info

    with Guard("· packing..."):
        commit = ctx.get("SHORT_COMMIT_HASH")
        version = ctx.get("LOCAL_VERSION")
        timestamp = ctx.get("TIMESTAMP")
        date = datetime.fromisoformat(timestamp).strftime("%Y-%m-%d")

        app_path = ctx.get("APP_PATH")
        local_app_path = ctx.get("LOCAL_APP_PATH")

        artifact_name = f"pubpublica--{date}--{version}--{commit}"
        artifact_ext = ".tar.gz"
        artifact_file = artifact_name + artifact_ext

        artifact_dir = os.path.abspath("build/")
        artifact_path = os.path.join(artifact_dir, artifact_file)

        ctx.update({"ARTIFACT_ID": artifact_name})
        ctx.update({"ARTIFACT_FILE": artifact_file})
        ctx.update({"ARTIFACT_LOCAL_PATH": artifact_path})

        deploy_path = os.path.join(app_path, artifact_name)
        ctx.update({"DEPLOY_PATH": deploy_path})

        includes = ctx.get("INCLUDES") or []
        paths = [os.path.join(local_app_path, i) for i in includes]

        with tarfile.open(artifact_path, "w:gz") as tar:
            for name, path in zip(includes, paths):
                tar.add(path, arcname=name, filter=_tar_filter)

        md5 = hashlib.md5()
        block_size = 65536
        with open(artifact_path, "rb") as f:
            while data := f.read(block_size):
                md5.update(data)

        ctx.update({"ARTIFACT_MD5": md5.hexdigest()})
示例#10
0
def build_context(c):
    with Guard("· gathering build information..."):
        config = util.template("pubpublica.json")

        context = {}
        context.update(config.get("BUILD", {}))

        local_config_path = os.path.abspath(context.get("LOCAL_CONFIG_PATH"))
        context.update({"LOCAL_CONFIG_PATH": local_config_path})

        local_app_path = os.path.abspath(context.get("LOCAL_APP_PATH"))
        context.update({"LOCAL_APP_PATH": local_app_path})

        context.update(config.get("PROVISION", {}))
        context.update(config.get("DEPLOY", {}))

        if pubpublica_config := config.get("PUBPUBLICA"):
            context.update({"PUBPUBLICA": pubpublica_config})

        if flask_config := config.get("FLASK"):
            context.update({"FLASK": flask_config})
示例#11
0
def transfer_project(c, ctx):
    with Guard("· transferring..."):
        local_artifact = ctx.get("ARTIFACT_LOCAL_PATH")
        if not local_artifact:
            raise Exception("no artifact to deployed")

        if not os.path.isfile(local_artifact):
            raise Exception("artifact to be deployed is not a file")

        deploy_path = ctx.get("DEPLOY_PATH")
        if not fs.create_directory(c, deploy_path, sudo=True):
            raise Exception("unable to create {deploy_path} on server")

        artifact_file = ctx.get("ARTIFACT_FILE")
        artifact_path = os.path.join(deploy_path, artifact_file)

        temp_path = "/tmp"
        remote_artifact = os.path.join(temp_path, artifact_file)

        # if transfer fails, an exception is raised
        c.put(local_artifact, remote=remote_artifact)
        fs.move(c, remote_artifact, artifact_path, sudo=True)
示例#12
0
def restart_service(c, service):
    with Guard(f"· restarting {service} service..."):
        if not systemd.restart(c, service, sudo=True):
            raise GuardWarning(f"Failed to restart the {service} service")
示例#13
0
    fs.move(c, tmpfile, remote_path, sudo=True)


def setup_flask(c, ctx):
    # TODO: merge with setup_pubpublica?
    print("setting up flask")
    local_config_path = ctx.get("LOCAL_CONFIG_PATH")
    deploy_path = ctx.get("DEPLOY_PATH")

    if not (cfg := ctx.get("FLASK") or {}):
        log.warning("unable to locate flask config")

    if not (template_file := cfg.get("FLASK_CONFIG_FILE")):
        raise Exception("path to flask config template is not set")

    with Guard("· building config files..."):
        if path := cfg.get("FLASK_SECRET_KEY_PATH"):
            pw = PASS.get(path)
            cfg.update({"FLASK_SECRET_KEY": pw})
            cfg.pop("FLASK_SECRET_KEY_PATH", None)

        config_path = ctx.get("LOCAL_CONFIG_PATH")
        template_path = os.path.join(config_path, template_file)
        remote_path = os.path.join(deploy_path, template_file)
        render_and_upload(c, template_path, remote_path, cfg)


def setup_redis(c, ctx):
    print("setting up redis")
    local_config_path = ctx.get("LOCAL_CONFIG_PATH")
    deploy_path = ctx.get("DEPLOY_PATH")