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
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()
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({})
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)
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))
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)})
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)
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})
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)
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)
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)
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)})
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)
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)})
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)})
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)
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'})
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)
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)})
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)
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"}
def project_get(proj): p = get_or_404(Project.query.filter_by(name=proj)) return jsendify({'project': p.as_json(detailed=True)})
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]})