Example #1
0
def build_cancel(proj, build_id):
    permissions.assert_can_build(proj)
    p = get_or_404(Project.query.filter_by(name=proj))
    b = get_or_404(Build.query.filter_by(project=p, build_id=build_id))
    for r in b.runs:
        r.cancel()
    return jsendify({}), 202
Example #2
0
def _get_run(proj, build_id, run):
    p = get_or_404(Project.query.filter_by(name=proj))
    b = get_or_404(Build.query.filter_by(project=p, build_id=build_id))
    return Run.query.filter_by(
        name=run
    ).filter(
        Run.build.has(Build.id == b.id)
    ).first_or_404()
Example #3
0
def project_patch_trigger(proj, tid):
    permissions.assert_can_build(proj)
    trigger = get_or_404(ProjectTrigger.query.filter(ProjectTrigger.id == tid))
    if trigger.project.name != proj:
        # someone is trying to do something fishy
        return jsendify({}, 404)

    data = request.get_json() or {}
    val = data.get('definition_file')
    if val:
        trigger.definition_file = val

    val = data.get('definition_repo')
    if val:
        trigger.definition_repo = val

    val = data.get('secrets')
    if val:
        # convert array of [{'name': <name>, 'value': <value>}, ...] dicts
        # into dictionary of {<name>: <value>, ...}
        current_secrets = trigger.secret_data
        for secret in val:
            name, value = secret['name'], secret['value']
            if value is None:
                if name in current_secrets:
                    del current_secrets[name]
            else:
                current_secrets[name] = value
        trigger.update_secrets()
    db.session.commit()
    return jsendify({})
Example #4
0
def create_webhook(proj):
    u = permissions.assert_internal_user()
    p = get_or_404(Project.query.filter_by(name=proj))

    d = request.get_json() or {}
    required = ('githubtok', 'owner', 'project')
    missing = []
    for x in required:
        if x not in d:
            missing.append(x)
    if missing:
        raise ApiError(401, 'Missing parameters: %s' % ','.join(missing))

    owner = d.pop('owner')
    hook_url = 'https://api.github.com/repos/%s/%s/hooks'
    hook_url = hook_url % (owner, d.pop('project'))

    d['webhook-key'] = secrets.token_urlsafe()
    dr = df = None
    try:
        dr = d.pop('definition_repo')
        df = d.pop('definition_file')
    except KeyError:
        pass

    user = owner
    if u:
        user = str(u)

    db.session.add(ProjectTrigger(
        user, TriggerTypes.github_pr.value, p, dr, df, d))

    _register_github_hook(p, hook_url, d['githubtok'], d['webhook-key'])
    db.session.commit()
    return jsendify({}, 201)
Example #5
0
def promoted_build_list(proj):
    p = get_or_404(Project.query.filter_by(name=proj))
    q = (Build.query.filter(Build.proj_id == p.id).filter(
        Build.status == BuildStatus.PROMOTED).order_by(Build.id.desc()))

    s = Storage()
    return paginate_custom("builds", q, lambda x: _promoted_as_json(s, x))
Example #6
0
def promoted_build_get(proj, name):
    b = get_or_404(Build.query.join(Project).filter(
        Project.name == proj,
        Build.status == BuildStatus.PROMOTED,
        Build.name == name,
    ))
    return jsendify({'build': _promoted_as_json(Storage(), b)})
Example #7
0
def project_create_trigger(proj):
    u = permissions.assert_internal_user()
    p = get_or_404(Project.query.filter_by(name=proj))

    d = request.get_json() or {}
    ttype = d.pop('type')
    if not ttype:
        raise ApiError(401, 'Missing parameter: type')
    ttype = TriggerTypes[ttype].value

    try:
        owner = d.pop('owner')
    except KeyError:
        owner = 'unknown-internal'
    if u:
        owner = str(u)
    dr = df = None
    try:
        dr = d.pop('definition_repo')
        df = d.pop('definition_file')
    except KeyError:
        pass

    try:
        secrets = d.pop('secrets')
        # convert array of [{'name': <name>, 'value': <value>}, ...] dicts
        # into dictionary of {<name>: <value>, ...}
        secrets = {x['name']: x['value'] for x in secrets}
    except KeyError:
        secrets = d

    db.session.add(ProjectTrigger(owner, ttype, p, dr, df, secrets))

    db.session.commit()
    return jsendify({}, 201)
Example #8
0
def worker_get(name):
    w = get_or_404(Worker.query.filter_by(name=name))

    data = w.as_json(detailed=True)
    if _is_worker_authenticated(w):
        data['version'] = WORKER_SCRIPT_VERSION

        if w.enlisted:
            w.ping(**request.args)

        runners = int(request.args.get('available_runners', '0'))
        if runners > 0 and w.available:
            r = Run.pop_queued(w)
            if r:
                try:
                    s = Storage()
                    with s.console_logfd(r, 'a') as f:
                        f.write("# Run sent to worker: %s\n" % name)
                    data['run-defs'] = [_fix_run_urls(s.get_run_definition(r))]
                    r.build.refresh_status()
                except:
                    r.worker = None
                    r.status = 'QUEUED'
                    db.session.commit()
                    raise

    return jsendify({'worker': data})
Example #9
0
def build_promote(proj, build_id):
    permissions.assert_can_promote(proj, build_id)
    p = get_or_404(Project.query.filter_by(name=proj))
    b = get_or_404(Build.query.filter_by(project=p, build_id=build_id))

    if not b.complete:
        raise ApiError(400, "Build is not yet complete")

    data = request.get_json()
    if not data:
        raise ApiError(400, "Input data must be JSON")

    b.status = BuildStatus.PROMOTED
    b.name = data.get("name")
    b.annotation = data.get("annotation")
    db.session.commit()
    return jsendify({}, 201)
Example #10
0
def worker_event(name):
    w = get_or_404(Worker.query.filter_by(name=name, deleted=False))
    if not w.enlisted:
        return jsendify({}, 403)
    payload = request.get_json()
    if payload:
        w.log_event(payload)
    return jsendify({}, 201)
Example #11
0
def worker_update(name):
    w = get_or_404(Worker.query.filter_by(name=name, deleted=False))
    data = request.get_json() or {}
    attrs = ('distro', 'mem_total', 'cpu_total', 'cpu_type',
             'concurrent_runs', 'host_tags')
    for attr in attrs:
        val = data.get(attr)
        if val is not None:
            setattr(w, attr, val)
    db.session.commit()
    return jsendify({}, 200)
Example #12
0
def build_get_latest(proj):
    '''Return the most recent successful build'''
    qs = Build.query.join(Build.project).filter(
        Project.name == proj,
        Build.status == BuildStatus.PASSED,
    )
    trigger = request.args.get('trigger_name')
    if trigger:
        qs = qs.filter(Build.trigger_name == trigger)
    b = get_or_404(qs.order_by(Build.id.desc()))
    return jsendify({'build': b.as_json(detailed=True)})
Example #13
0
 def wrapper(*args, **kwargs):
     key = request.headers.get('Authorization', None)
     if not key:
         return jsendify('No Authorization header provided', 401)
     parts = key.split(' ')
     if len(parts) != 2 or parts[0] != 'Token':
         return jsendify('Invalid Authorization header', 401)
     worker = get_or_404(Worker.query.filter_by(name=kwargs['name']))
     if not worker.validate_api_key(parts[1]):
         return jsendify('Incorrect API key for host', 401)
     return f(*args, **kwargs)
Example #14
0
def build_get_latest(proj):
    '''Return the most recent successful build'''
    b = get_or_404(
        Build.query.join(
            Build.project
        ).filter(
            Project.name == proj,
            Build.status == BuildStatus.PASSED,
        ).order_by(
            Build.id.desc()
        )
    )
    return jsendify({'build': b.as_json(detailed=True)})
Example #15
0
def build_get_latest(proj):
    """Return the most recent successful build"""
    status = BuildStatus.PASSED
    promoted = request.args.get("promoted")
    if promoted:
        status = BuildStatus.PROMOTED
    qs = Build.query.join(Build.project).filter(
        Project.name == proj,
        Build.status == status,
    )
    trigger = request.args.get("trigger_name")
    if trigger:
        qs = qs.filter(Build.trigger_name == trigger)
    b = get_or_404(qs.order_by(Build.id.desc()))
    return jsendify({"build": b.as_json(detailed=True)})
Example #16
0
def project_trigger_list(proj):
    permissions.assert_can_build(proj)
    p = get_or_404(Project.query.filter_by(name=proj))
    triggers = p.triggers

    t = request.args.get("type")
    if t:
        triggers = [x for x in triggers if x.type == TriggerTypes[t].value]

    # Remove the secret values, no need to ever expose them
    redacted = []
    for t in triggers:
        data = t.as_json()
        data["secrets"] = [{"name": x} for x in (data.get("secrets") or {}).keys()]
        redacted.append(data)
    return jsendify(redacted)
Example #17
0
def project_delete(proj):
    permissions.assert_can_delete(proj)

    p = get_or_404(Project.query.filter_by(name=proj))

    if request.get_json().get('I_REALLY_MEAN_TO_DO_THIS') != 'YES':
        raise ApiError(401, 'Missing required parameter: "name"')

    for t in p.triggers:
        db.session.delete(t)
    db.session.commit()

    for b in p.builds:
        db.session.delete(b)
    db.session.commit()

    db.session.delete(p)
    db.session.commit()
    return jsendify({'TODO': 'Delete storage artifacts'})
Example #18
0
    def wrapper(*args, **kwargs):
        key = request.headers.get("Authorization", None)
        if not key:
            return jsendify("No Authorization header provided", 401)
        parts = key.split(" ")
        if len(parts) != 2 or parts[0] not in ("Token", "Bearer"):
            return jsendify("Invalid Authorization header", 401)

        if parts[0] == "Bearer":
            try:
                w = worker_from_jwt(parts[1])
            except PyJWTError as e:
                return jsendify(str(e), 401)

            if w.name != kwargs["name"]:
                # worker can only access its self
                return jsendify("Not found", 404)

            worker = Worker.query.filter(Worker.name == w.name).first()
            if worker is None:
                # This looks a little nutty - constructing this object with
                # basically "I have no idea" data. But the worker will call
                # us with `worker_update` on its first connection which will
                # fill these handy but not mission-cricital fields out.
                worker = Worker(w.name, "?", 1, 1, "?", "", 1, w.allowed_tags)
                worker.enlisted = True
                db.session.add(worker)
                db.session.commit()
            elif worker.deleted:
                return jsendify("Not found", 404)

            worker.allowed_tags = w.allowed_tags
        else:
            worker = get_or_404(
                Worker.query.filter_by(name=kwargs["name"], deleted=False))
            if not worker.validate_api_key(parts[1]):
                return jsendify("Incorrect API key for host", 401)
            worker.allowed_tags = []
        request.worker = worker
        return f(*args, **kwargs)
Example #19
0
def build_get(proj, build_id):
    p = get_or_404(Project.query.filter(Project.name == proj))
    b = get_or_404(
        Build.query.filter(Build.project == p, Build.build_id == build_id))
    return jsendify({"build": b.as_json(detailed=True)})
Example #20
0
def build_list(proj):
    p = get_or_404(Project.query.filter(Project.name == proj))
    q = Build.query.filter_by(proj_id=p.id).order_by(Build.id.desc())
    return paginate("builds", q)
Example #21
0
def build_get_project_definition(proj, build_id):
    p = get_or_404(Project.query.filter(Project.name == proj))
    b = get_or_404(
        Build.query.filter(Build.project == p, Build.build_id == build_id))
    pd = Storage().get_project_definition(b)
    return pd, 200, {"Content-Type": "text/yaml"}
Example #22
0
def project_get(proj):
    p = get_or_404(Project.query.filter_by(name=proj))
    return jsendify({'project': p.as_json(detailed=True)})
Example #23
0
def run_list(proj, build_id):
    p = get_or_404(Project.query.filter_by(name=proj))
    b = get_or_404(Build.query.filter_by(project=p, build_id=build_id))
    return jsendify({'runs': [x.as_json(detailed=False) for x in b.runs]})