示例#1
0
 def setUp(self):
     self.lp_for_snaps = Launchpad(
         username="******",
         token=getenv("SNAP_BUILDS_TOKEN", "secret"),
         secret=getenv("SNAP_BUILDS_SECRET", "secret"),
         session=requests.Session(),
     )
     return super().setUp()
示例#2
0
    def test_01_build_image(self):
        lp_for_images = Launchpad(
            username="******",
            token=getenv("IMAGE_BUILDS_TOKEN", "secret"),
            secret=getenv("IMAGE_BUILDS_SECRET", "secret"),
            session=requests.Session(),
        )

        response = lp_for_images.build_image(board="cm3",
                                             system="core16",
                                             snaps=["code", "toto"])

        self.assertEqual(response.status_code, 201)
示例#3
0
class LaunchpadTest(VCRTestCase):
    def _get_vcr_kwargs(self):
        """
        This removes the authorization header
        from VCR so we don't record auth parameters
        """
        return {"filter_headers": ["Authorization"]}

    def setUp(self):
        self.lp_for_snaps = Launchpad(
            username="******",
            token=getenv("SNAP_BUILDS_TOKEN", "secret"),
            secret=getenv("SNAP_BUILDS_SECRET", "secret"),
            session=requests.Session(),
        )
        return super().setUp()

    def test_01_build_image(self):
        lp_for_images = Launchpad(
            username="******",
            token=getenv("IMAGE_BUILDS_TOKEN", "secret"),
            secret=getenv("IMAGE_BUILDS_SECRET", "secret"),
            session=requests.Session(),
        )

        response = lp_for_images.build_image(board="cm3",
                                             system="core16",
                                             snaps=["code", "toto"])

        self.assertEqual(response.status_code, 201)

    def test_02_get_snap_by_store_name(self):
        snap = self.lp_for_snaps.get_snap_by_store_name("toto")
        self.assertEqual("toto", snap["store_name"])

        snap = self.lp_for_snaps.get_snap_by_store_name(
            "snap-that-does-not-exist")
        self.assertEqual(None, snap)

    def test_03_create_snap(self):
        snap_name = "new-test-snap"
        git_repo = "https://github.com/build-staging-snapcraft-io/test1"
        self.lp_for_snaps.create_snap(snap_name, git_repo, "macaroon")

        # Check that the snap exist
        new_snap = self.lp_for_snaps.get_snap_by_store_name("new-test-snap")
        self.assertEqual(git_repo, new_snap["git_repository_url"])

    def test_04_build_snap(self):
        result = self.lp_for_snaps.build_snap("toto")
        self.assertEqual(True, result)
示例#4
0
def notify_build():
    """
    An endpoint to trigger an update about a build event to be sent.
    This will usually be triggered by a webhook from Launchpad
    """

    # Verify contents
    signature = hmac.new(
        flask.current_app.config["SECRET_KEY"].encode("utf-8"),
        flask.request.data,
        hashlib.sha1,
    ).hexdigest()

    if "X-Hub-Signature" not in flask.request.headers:
        return "No X-Hub-Signature provided\n", 403

    if not hmac.compare_digest(
        signature, flask.request.headers["X-Hub-Signature"].split("=")[1]
    ):
        try:
            raise HTTPError(400)
        except HTTPError:
            flask.current_app.extensions["sentry"].captureException(
                extra={
                    "request_headers": str(flask.request.headers.keys()),
                    "message": "x-hub-signature did not match",
                    "expected_signature": signature,
                    "header_contents": flask.request.headers[
                        "X-Hub-Signature"
                    ],
                    "extracted_signature": flask.request.headers[
                        "X-Hub-Signature"
                    ].split("=")[1],
                }
            )

        return "X-Hub-Signature does not match\n", 400

    event_content = flask.request.json
    status = event_content["status"]
    build_url = (
        "https://api.launchpad.net/devel" + event_content["livefs_build"]
    )

    launchpad = Launchpad(
        username=os.environ["LAUNCHPAD_IMAGE_BUILD_USER"],
        token=os.environ["LAUNCHPAD_IMAGE_BUILD_TOKEN"],
        secret=os.environ["LAUNCHPAD_IMAGE_BUILD_SECRET"],
        session=session,
        auth_consumer=os.environ["LAUNCHPAD_IMAGE_BUILD_AUTH_CONSUMER"],
    )

    build = launchpad.request(build_url).json()
    author_json = (
        gnupg.GPG()
        .decrypt(
            build["metadata_override"]["_author_data"],
            passphrase=flask.current_app.config["SECRET_KEY"],
        )
        .data
    )

    if author_json:
        author = json.loads(author_json)
    else:
        return "_author_data could not be decoded\n", 400

    email = author["email"]
    names = author["name"].split(" ")
    board = author["board"]
    snaps = ", ".join(build["metadata_override"]["extra_snaps"])
    codename = build["distro_series_link"].split("/")[-1]
    version = Data().by_codename(codename).version
    arch = build["distro_arch_series_link"].split("/")[-1]
    build_link = build["web_link"]
    build_id = build_link.split("/")[-1]

    download_url = None

    if status == "Successfully built":
        download_url = launchpad.request(
            f"{build_url}?ws.op=getFileUrls"
        ).json()[0]

    session.post(
        "https://pages.ubuntu.com/index.php/leadCapture/save",
        data={
            "FirstName": " ".join(names[:-1]),
            "LastName": names[-1] if len(names) > 1 else "",
            "Email": email,
            "formid": "3546",
            "lpId": "2154",
            "subId": "30",
            "munchkinId": "066-EOV-335",
            "imageBuilderVersion": version,
            "imageBuilderArchitecture": arch,
            "imageBuilderBoard": board,
            "imageBuilderSnaps": snaps,
            "imageBuilderID": build_id,
            "imageBuilderBuildlink": build_link,
            "imageBuilderStatus": status,
            "imageBuilderDownloadlink": download_url,
        },
    )

    return "Submitted\n", 202
示例#5
0
def post_build():
    """
    Once they submit the build form on /core/build,
    kick off the build with Launchpad
    """

    opt_in = flask.request.values.get("canonicalUpdatesOptIn")
    full_name = flask.request.values.get("FullName")
    names = full_name.split(" ")
    email = flask.request.values.get("Email")
    board = flask.request.values.get("board")
    system = flask.request.values.get("system")
    snaps = flask.request.values.get("snaps", "").split(",")
    arch = flask.request.values.get("arch")

    if not user_info(flask.session):
        flask.abort(401)

    launchpad = Launchpad(
        username=os.environ["LAUNCHPAD_IMAGE_BUILD_USER"],
        token=os.environ["LAUNCHPAD_IMAGE_BUILD_TOKEN"],
        secret=os.environ["LAUNCHPAD_IMAGE_BUILD_SECRET"],
        session=session,
        auth_consumer=os.environ["LAUNCHPAD_IMAGE_BUILD_AUTH_CONSUMER"],
    )

    context = {}

    # Submit user to marketo
    session.post(
        "https://pages.ubuntu.com/index.php/leadCapture/save",
        data={
            "canonicalUpdatesOptIn": opt_in,
            "FirstName": " ".join(names[:-1]),
            "LastName": names[-1] if len(names) > 1 else "",
            "Email": email,
            "formid": "3546",
            "lpId": "2154",
            "subId": "30",
            "munchkinId": "066-EOV-335",
            "imageBuilderStatus": "NULL",
        },
    )

    # Ensure webhook is created
    if flask.request.host == "ubuntu.com":
        launchpad.create_update_system_build_webhook(
            system=system,
            delivery_url="https://ubuntu.com/core/build/notify",
            secret=flask.current_app.config["SECRET_KEY"],
        )

    # Kick off image build
    try:
        response = launchpad.build_image(
            board=board,
            system=system,
            snaps=snaps,
            author_info={"name": full_name, "email": email, "board": board},
            gpg_passphrase=flask.current_app.config["SECRET_KEY"],
            arch=arch,
        )
        context["build_info"] = launchpad.session.get(
            response.headers["Location"]
        ).json()
    except HTTPError as http_error:
        if http_error.response.status_code == 400:
            return (
                flask.render_template(
                    "core/build/error.html",
                    build_error=http_error.response.content.decode(),
                ),
                400,
            )
        else:
            raise http_error

    return flask.render_template("core/build/index.html", **context)
示例#6
0
import json
import os

import flask
from canonicalwebteam.launchpad import Launchpad
from ruamel.yaml import YAML
from webapp.api.requests import PublisherSession, Session

_yaml = YAML(typ="rt")
_yaml_safe = YAML(typ="safe")
api_session = Session()
api_publisher_session = PublisherSession()

launchpad = Launchpad(
    username=os.getenv("LP_API_USERNAME"),
    token=os.getenv("LP_API_TOKEN"),
    secret=os.getenv("LP_API_TOKEN_SECRET"),
    session=api_publisher_session,
)


def get_yaml_loader(typ="safe"):
    if typ == "safe":
        return _yaml_safe
    return _yaml


def get_licenses():
    try:
        with open("webapp/licenses.json") as f:
            licenses = json.load(f)["licenses"]
示例#7
0
# Local
from webapp.api import dashboard as api
from webapp.api.exceptions import ApiError, ApiResponseErrorList
from webapp.api.github import GitHub, InvalidYAML
from webapp.decorators import login_required
from webapp.extensions import csrf
from webapp.publisher.snaps.builds import map_build_and_upload_states
from webapp.publisher.views import _handle_error, _handle_error_list
from werkzeug.exceptions import Unauthorized

GITHUB_SNAPCRAFT_USER_TOKEN = os.getenv("GITHUB_SNAPCRAFT_USER_TOKEN")
BUILDS_PER_PAGE = 15
launchpad = Launchpad(
    username=os.getenv("LP_API_USERNAME"),
    token=os.getenv("LP_API_TOKEN"),
    secret=os.getenv("LP_API_TOKEN_SECRET"),
    session=talisker.requests.get_session(),
)


def get_builds(lp_snap, selection):
    builds = launchpad.get_snap_builds(lp_snap["store_name"])

    total_builds = len(builds)

    builds = builds[selection]

    snap_builds = []

    for build in builds:
        status = map_build_and_upload_states(build["buildstate"],
class LaunchpadTest(VCRTestCase):
    def _get_vcr_kwargs(self):
        """
        This removes the authorization header
        from VCR so we don't record auth parameters
        """
        return {"filter_headers": ["Authorization"]}

    def setUp(self):
        self.lp_for_snaps = Launchpad(
            username="******",
            token=getenv("SNAP_BUILDS_TOKEN", "secret"),
            secret=getenv("SNAP_BUILDS_SECRET", "secret"),
            session=requests.Session(),
        )
        self.lp_for_images = Launchpad(
            username="******",
            token=getenv("IMAGE_BUILDS_TOKEN", "secret"),
            secret=getenv("IMAGE_BUILDS_SECRET", "secret"),
            session=requests.Session(),
        )
        return super().setUp()

    def test_01_build_image(self):
        response = self.lp_for_images.build_image(
            board="cm3",
            system="core16",
            snaps=["code", "toto"],
            author_info={
                "name": "somename",
                "email": "someemail"
            },
            gpg_passphrase="fakepassword",
        )

        self.assertEqual(response.status_code, 201)

    def test_02_create_webhooks(self):
        print(getenv("IMAGE_BUILDS_TOKEN", "secret"))
        print(getenv("IMAGE_BUILDS_SECRET", "secret"))
        with self.assertRaises(WebhookExistsError):
            self.lp_for_images.create_system_build_webhook(
                "core18",
                "https://design.staging.ubuntu.com/?image.build",
                "fake-secret",
            )

        response = self.lp_for_images.create_system_build_webhook(
            "classic18.04",
            "https://design.staging.ubuntu.com/?image.build",
            "fake-secret",
        )

        self.assertEqual(response.status_code, 201)

    def test_03_get_snap_by_store_name(self):
        snap = self.lp_for_snaps.get_snap_by_store_name("toto")
        self.assertEqual("toto", snap["store_name"])

        snap = self.lp_for_snaps.get_snap_by_store_name(
            "snap-that-does-not-exist")
        self.assertEqual(None, snap)

    def test_04_create_snap(self):
        snap_name = "new-test-snap"
        git_repo = "https://github.com/build-staging-snapcraft-io/test1"
        self.lp_for_snaps.create_snap(snap_name, git_repo, "macaroon")

        # Check that the snap exist
        new_snap = self.lp_for_snaps.get_snap_by_store_name("new-test-snap")
        self.assertEqual(git_repo, new_snap["git_repository_url"])

    def test_05_build_snap(self):
        result = self.lp_for_snaps.build_snap("toto")
        self.assertEqual(True, result)

    def test_05_delete_snap(self):
        result = self.lp_for_snaps.delete_snap("new-test-snap")
        self.assertEqual(True, result)
示例#9
0
from canonicalwebteam.launchpad import Launchpad
from requests import Session
from sentry_sdk import capture_exception, init
from sentry_sdk.integrations.logging import ignore_logger

from src import helper
from src.exceptions import GitHubRateLimit, InvalidGitHubRepo
from src.github import GitHub

# Set up Sentry
init(os.getenv("SENTRY_DSN"))
ignore_logger("script.output")

launchpad = Launchpad(
    username="******",
    token=os.getenv("LP_API_TOKEN"),
    secret=os.getenv("LP_API_TOKEN_SECRET"),
    session=Session(),
)

github = GitHub(os.getenv("GITHUB_SNAPCRAFT_POLLER_TOKENS").split(), Session())

# Skip Snaps built in the last 24 hours
threshold = datetime.datetime.now() - dateutil.relativedelta.relativedelta(
    days=1)


def needs_building(snap, logger):
    if not snap["store_name"]:
        logger.info(
            f"SKIP {snap['name']}: Launchpad snap doesn't have store name")
        return False