diff --git a/etc/bash_completion.d/curl-inau b/etc/bash_completion.d/curl-inau deleted file mode 100644 index 4661dfde1e0a741f40d92ed22df9d069b658ea3f..0000000000000000000000000000000000000000 --- a/etc/bash_completion.d/curl-inau +++ /dev/null @@ -1,90 +0,0 @@ -function ispresent() { - for item in $2 - do - if [ $item = $1 ]; then - return 0 - fi - done - return 1 -} - -function _curl-inau() -{ - local h options dirname basename - h=inau.elettra.eu - dirname=$(dirname "${COMP_WORDS[COMP_CWORD]}") - basename=$(basename "${COMP_WORDS[COMP_CWORD]}") - -# echo -e "\n$dirname#$basename" - case "$dirname#$basename" in - //$h/v2/cs/facilities/*/hosts/*/files#*) - local facility=$(basename $(dirname $(dirname $(dirname $dirname)))) - local host=$(basename $(dirname $dirname)) - local files="$(curl -s https://$h/v2/cs/facilities/$facility/hosts/$host/files | tail -n +3 | cut -d" " -f1)" - options="$(for elem in $files; do echo //$h/v2/cs/facilities/$facility/hosts/$host/files/$elem; done)" - ;; - //$h/v2/cs/facilities/*/hosts/*#files) - local facility=$(basename $(dirname $(dirname $dirname))) - local host=$(basename $dirname) - local files="$(curl -s https://$h/v2/cs/facilities/$facility/hosts/$host/files | tail -n +3 | cut -d" " -f1)" - options="$(for elem in $files; do echo //$h/v2/cs/facilities/$facility/hosts/$host/files/$elem; done)" - ;; - //$h/v2/cs/facilities/*/hosts/*#*) - local facility=$(basename $(dirname $(dirname $dirname))) - local host=$(basename $dirname) - options="//$h/v2/cs/facilities/$facility/hosts/$host/files - //$h/v2/cs/facilities/$facility/hosts/$host/installations" - ;; - //$h/v2/cs/facilities/*/hosts#*) - local facility=$(basename $(dirname $dirname)) - local hosts="$(curl -s https://$h/v2/cs/facilities/$facility/hosts | tail -n +3 | cut -d" " -f1)" - ispresent $basename "$hosts" - if [ $? -eq 0 ]; then - options="//$h/v2/cs/facilities/$facility/hosts/$basename/installations - //$h/v2/cs/facilities/$facility/hosts/$basename/files" - else - options="//$h/v2/cs/facilities/$facility/hosts/installations - $(for elem in $hosts; do echo //$h/v2/cs/facilities/$facility/hosts/$elem; done)" - fi;; - - //$h/v2/cs/facilities/*#hosts) - local facility=$(basename $dirname) - local hosts="$(curl -s https://$h/v2/cs/facilities/$facility/hosts | tail -n +3 | cut -d" " -f1)" - options="//$h/v2/cs/facilities/$facility/hosts/installations - $(for elem in $hosts; do echo //$h/v2/cs/facilities/$facility/hosts/$elem; done)" - ;; - //$h/v2/cs/facilities/*#*) - local facility=$(basename $dirname) - options="//$h/v2/cs/facilities/$facility/hosts - //$h/v2/cs/facilities/$facility/installations" - ;; - //$h/v2/cs/facilities#*) - local facilities="$(curl -s https://$h/v2/cs/facilities | tail -n +3)" - ispresent $basename "$facilities" - if [ $? -eq 0 ]; then - options="//$h/v2/cs/facilities/$basename/hosts/ - //$h/v2/cs/facilities/$basename/installations" - else - options="//$h/v2/cs/facilities/installations - $(for elem in $facilities; do echo //$h/v2/cs/facilities/$elem/; done)" - fi - ;; - //$h/v2/cs#facilities) - local facilities="$(curl -s https://$h/v2/cs/facilities | tail -n +3)" - options="//$h/v2/cs/facilities/installations - $(for elem in $facilities; do echo //$h/v2/cs/facilities/$elem/; done)" - ;; - //$h/v2#cs | //$h/v2/cs#*) - local subpaths="$(curl -s https://$h/v2/cs | tail -n +3)" - options="//$h/v2/cs/installations - $(for elem in $subpaths; do echo //$h/v2/cs/$elem/; done)" - ;; - /#$h | //$h#* | //$h/v2#*) - options="//$h/v2/cs/" - ;; - - esac - COMPREPLY=($(compgen -W "${options}" -- "${COMP_WORDS[COMP_CWORD]}")) - compopt -o nospace -} -complete -F _curl-inau curl diff --git a/etc/skel/.curlrc b/etc/skel/.curlrc deleted file mode 100644 index cd8d32a1dc465c087d92dd2197625a12d475a8dc..0000000000000000000000000000000000000000 --- a/etc/skel/.curlrc +++ /dev/null @@ -1,3 +0,0 @@ -header "Accept: text/plain" -write-out \n -silent diff --git a/inau-dispatcher.py b/inau-dispatcher.py deleted file mode 100644 index a58dc4f1e769877aef877808d177441328bfcaf8..0000000000000000000000000000000000000000 --- a/inau-dispatcher.py +++ /dev/null @@ -1,432 +0,0 @@ -#!/usr/bin/env python3 - -from http.server import BaseHTTPRequestHandler, HTTPServer -from http import HTTPStatus -import ssl -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker, exc -from multiprocessing import Process, Queue -from enum import Enum, IntEnum -import os -import signal -import json -import sys -import logging -import logging.handlers -import argparse -import datetime -import subprocess -import paramiko -import hashlib -import shutil -from smtplib import SMTP -from email.mime.text import MIMEText -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, ForeignKey, func -from sqlalchemy.orm import relationship -from enum import Enum, IntEnum -import datetime - -Session = sessionmaker() - -allbuilders = {} -users = {} - -Base = declarative_base() - -class Users(Base): - __tablename__ = 'users' - id = Column(Integer, primary_key=True) - name = Column(String(255), unique=True, nullable=False) - admin = Column(Boolean, default=False, nullable=False) - notify = Column(Boolean, default=False, nullable=False) - -class Architectures(Base): - __tablename__ = 'architectures' - id = Column(Integer, primary_key=True) - name = Column(String(255), unique=True, nullable=False) - platforms = relationship('Platforms', back_populates='architecture') - -class Distributions(Base): - __tablename__ = 'distributions' - id = Column(Integer, primary_key=True) - name = Column(String(255), nullable=False) - version = Column(String(255), nullable=False) - platforms = relationship('Platforms', back_populates='distribution') - -class Platforms(Base): - __tablename__ = 'platforms' - id = Column(Integer, primary_key=True) - distribution_id = Column(Integer, ForeignKey('distributions.id'), nullable=False) - architecture_id = Column(Integer, ForeignKey('architectures.id'), nullable=False) - architecture = relationship('Architectures', back_populates='platforms') - distribution = relationship('Distributions', back_populates='platforms') - -class Builders(Base): - __tablename__ = 'builders' - - id = Column(Integer, primary_key=True) - platform_id = Column(Integer, ForeignKey('platforms.id'), nullable=False) - name = Column(String(255), unique=False, nullable=False) - environment = Column(String(255), unique=False, nullable=True) - -class Providers(Base): - __tablename__ = 'providers' - - id = Column(Integer, primary_key=True) - url = Column(String(255), unique=True, nullable=False) - -class RepositoryType(IntEnum): - cplusplus = 0, - python = 1, - configuration = 2, - shellscript = 3, - library = 4 - -class Repositories(Base): - __tablename__ = 'repositories' - - id = Column(Integer, primary_key=True) - provider_id = Column(Integer, ForeignKey('providers.id'), nullable=False) - platform_id = Column(Integer, ForeignKey('platforms.id'), nullable=False) - type = Column(Integer, nullable=False) - name = Column(String(255), nullable=False) - destination = Column(String(255), nullable=False) - enabled = Column(Boolean, default=True, nullable=False) - -class Builds(Base): - __tablename__ = 'builds' - - id = Column(Integer, primary_key=True) - repository_id = Column(Integer, ForeignKey('repositories.id'), nullable=False) - platform_id = Column(Integer, ForeignKey('platforms.id'), nullable=False) - tag = Column(String(255), nullable=False) - date = Column(DateTime, default=datetime.datetime.now, nullable=False) - status = Column(Integer, nullable=True) - output = Column(Text, nullable=True) - -class Artifacts(Base): - __tablename__ = 'artifacts' - - id = Column(Integer, primary_key=True) - build_id = Column(Integer, ForeignKey('builds.id'), nullable=False) - hash = Column(String(255), nullable=True) - filename = Column(String(255), nullable=False) - symlink_target = Column(String(255), nullable=True) - -def __sendEmail(to_addrs, subject, body): - if to_addrs: - with SMTP(args.smtpserver + "." + args.smtpdomain, port=25) as smtpClient: - sender = args.smtpsender + "@" + args.smtpdomain - msg = MIMEText(body) - msg['Subject'] = "INAU. " + subject - msg['From'] = sender - msg['To'] = ', '.join(to_addrs) - d = smtpClient.sendmail(from_addr=sender, to_addrs=list(to_addrs), msg=msg.as_string()) - print("Email sent to ", list(to_addrs), d) - -def sendEmail(recipients, subject, body): - notifiable = set() - for user in users: - if (user.notify==True): - notifiable.add(user.name + "@" + args.smtpdomain) - to_addrs = set(recipients).intersection(notifiable) - __sendEmail(to_addrs, subject, body) - -def sendEmailAdmins(subject, body): - to_addrs = set() - for user in users: - if (user.admin==True): - to_addrs.add(user.name + "@" + args.smtpdomain) - __sendEmail(to_addrs, subject, body) - -class Die: - pass - -class Update: - def __init__(self, repository_name, repository_url, build_tag, default_branch): - self.repository_name = repository_name - self.repository_url = repository_url - self.build_tag = build_tag - self.default_branch = default_branch - -class Build(Update): - def __init__(self, repository_name, repository_url, build_tag, default_branch): - Update.__init__(self, repository_name, repository_url, build_tag, default_branch) - self.status = '' - self.output = '' - -class Store(Build): - def __init__(self, repository_name, repository_url, build_tag, repository_id, repository_type, emails, default_branch): - Build.__init__(self, repository_name, repository_url, build_tag, default_branch) - self.repository_id = repository_id - self.repository_type = repository_type - self.emails = emails - -class Builder: - def __init__(self, name, platform_id, environment): - self.name = name - self.platform_id = platform_id - self.platdir = args.repo + '/' + str(platform_id) - if environment is None: - self.environment = "" - else: - self.environment = "source " + environment + "; " - self.queue = Queue() - self.process = Process(target=self.handler) - self.process.start() - - def update(self, job): - logger.info("[" + self.name + "] Checkouting " + job.build_tag + " from " + job.repository_url + "...") - builddir = self.platdir + "/" + job.repository_name - buildcmd = "" - if not os.path.isdir(self.platdir): - os.mkdir(self.platdir) - - if not os.path.isdir(self.platdir + "/cs/ds/makefiles"): - buildcmd += "git clone --recurse-submodule https://gitlab.elettra.eu/cs/ds/makefiles.git " + self.platdir + "/cs/ds/makefiles" - else: - buildcmd += "git -C " + self.platdir + "/cs/ds/makefiles remote update" - buildcmd += " && git -C " + self.platdir + "/cs/ds/makefiles reset --hard origin/master" - - if not os.path.isdir(builddir): - buildcmd += " && git clone --recurse-submodule " + job.repository_url + " " + builddir - buildcmd += " && git -C " + builddir + " remote update" - buildcmd += " && git -C " + builddir + " pull --tags" - buildcmd += " && git -C " + builddir + " branch --no-color --contains " + job.build_tag + " | grep '\<" + job.default_branch + "\>'" - buildcmd += " && git -C " + builddir + " reset --hard " + job.build_tag + " --" - buildcmd += " && git -C " + builddir + " submodule update --init --force --recursive" - subprocess.run(buildcmd, shell=True, check=True) - - def build(self, job): - logging.info("[" + self.name + "] Building " + job.build_tag + " from " + job.repository_url + "...") - builddir = self.platdir + "/" + job.repository_name - with paramiko.SSHClient() as sshClient: - sshClient.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - sshClient.connect(hostname=self.name, port=22, username="inau", - key_filename="/home/inau/.ssh/id_rsa.pub") - if job.repository_type != RepositoryType.library: - _, raw, _ = sshClient.exec_command("(" + self.environment + "source /etc/profile; cd " + builddir - + "; make -j`getconf _NPROCESSORS_ONLN`) 2>&1") - else: - _, raw, _ = sshClient.exec_command("(" + self.environment + "source /etc/profile; cd " + builddir - + "; make -j`getconf _NPROCESSORS_ONLN` && rm -fr .install && PREFIX=.install make install) 2>&1") - job.status = raw.channel.recv_exit_status() - job.output = raw.read().decode('latin-1') # FIXME utf-8 is rejected by Mysql despite it is properly configured - - def store(self, job): - logging.info("[" + self.name + "] Storing " + job.build_tag + " from " + job.repository_url + "...") - - build = Builds(repository_id=job.repository_id, platform_id=self.platform_id, tag=os.path.basename(job.build_tag), - status=job.status, output=job.output) - self.session.add(build) - self.session.commit() - - builddir = self.platdir + "/" + job.repository_name - outcome = job.repository_name + " " + os.path.basename(job.build_tag) - if job.status != 0: - outcome += ": built failed on " + self.name - else: - outcome += ": built successfully on " + self.name - if job.repository_type == RepositoryType.cplusplus or job.repository_type == RepositoryType.python \ - or job.repository_type == RepositoryType.shellscript: - basedir = builddir + "/bin/" - elif job.repository_type == RepositoryType.configuration: - basedir = builddir + "/etc/" - elif job.repository_type == RepositoryType.library: - basedir = builddir + "/.install/" - else: - raiseException('Invalid type') - - artifacts = [] - for rdir_abs, _, fnames in os.walk(basedir): - for fname in fnames: - fname_abs = os.path.join(rdir_abs, fname) - rdir_rel = os.path.relpath(rdir_abs, basedir) - fname_rel = os.path.join(rdir_rel, fname) - if not os.path.islink(fname_abs): - with open(fname_abs,"rb") as fd: - bytes = fd.read() - hashFile = hashlib.sha256(bytes).hexdigest() - hashDir = hashFile[0:2] + "/" + hashFile[2:4] - if not os.path.isdir(args.store + hashDir): - os.makedirs(args.store + hashDir, exist_ok=True) - if not os.path.isfile(args.store + hashFile): - shutil.copyfile(fname_abs, args.store + hashDir + "/" + hashFile, follow_symlinks=False) - artifacts.append(Artifacts(build_id=build.id, hash=hashFile, filename=fname_rel)) - else: - artifacts.append(Artifacts(build_id=build.id, filename=fname_rel, - symlink_target=os.path.join(rdir_rel, os.readlink(fname_abs)))) - self.session.add_all(artifacts) - self.session.commit() - sendEmail(job.emails, outcome, job.output) - - def handler(self): - logger.info("[" + self.name + "] Starting process for builder " + self.name + "...") - - engine.dispose() - self.session = Session() - while True: - try: - job = self.queue.get() - if isinstance(job, Die): - logger.info("[" + self.name + "] Stopping process for builder " + self.name + "...") - break - - if isinstance(job, Update): - self.update(job) - - if isinstance(job, Build): - self.build(job) - - if isinstance(job, Store): - self.store(job) - - except subprocess.CalledProcessError as c: - sendEmailAdmins("Subprocess failed", str(c)) - logger.error("Subprocess failed: ", str(c)) - self.session.rollback() - except Exception as e: - sendEmailAdmins("Generic error", str(e)) - logger.error("Generic error: ", str(e)) - self.session.rollback() - except KeyboardInterrupt as k: - self.session.rollback() - break - finally: - self.session.close() - -def signalHandler(signalNumber, frame): - reconcile() - -def reconcile(): - logger.info('Reconciling...') - - session = Session() - try: - global allbuilders - global users - - users = session.query(Users).all() - - newbuilders = {} - oldbuilders = allbuilders - for b in session.query(Builders).all(): - try: - newbuilders[b.platform_id].append(Builder(b.name, b.platform_id, b.environment)) - except KeyError: - newbuilders[b.platform_id] = [Builder(b.name, b.platform_id, b.environment)] - allbuilders = newbuilders - - for oldbuilder in oldbuilders.values(): - for b in oldbuilder: - b.queue.put(Die()) - b.process.join() - except Exception as e: - sendEmailAdmins("Reconcilation failed", str(e)) - logger.error("Reconciliation failed: ", str(e)) - session.rollback() - finally: - session.close() - -class Server(BaseHTTPRequestHandler): - def do_POST(self): - engine.dispose() - session = Session() - try: - content_length = int(self.headers['Content-Length']) - post_data = self.rfile.read(content_length) - - if self.headers['Content-Type'] != 'application/json': - self.send_response(HTTPStatus.UNSUPPORTED_MEDIA_TYPE.value) - self.end_headers() - return - - post_json = json.loads(post_data.decode('utf-8')) - logger.debug(post_json) - print(post_json) - - # Tag deletion - if post_json['after'] == '0000000000000000000000000000000000000000': - self.send_response(HTTPStatus.OK.value) - self.end_headers() - return - - # Check if the tag is lightweight - if post_json['after'] == post_json['commits'][0]['id']: - self.send_response(HTTPStatus.OK.value) - self.end_headers() - return - - for r in session.query(Repositories).filter(Repositories.name==post_json['project']['path_with_namespace']).all(): - if self.headers['X-Gitlab-Event'] == 'Tag Push Hook' and post_json['event_name'] == 'tag_push' and r.enabled: - job = Store(repository_name = r.name, repository_url = post_json['project']['ssh_url'], build_tag=post_json['ref'], - repository_id = r.id, repository_type = r.type, emails=[post_json['commits'][0]['author']['email'], - post_json['user_username'] + '@elettra.eu', post_json['user_email']], - default_branch=post_json['project']['default_branch']) - else: - continue - - # Assign the job to the builder with shortest queue length - idx = allbuilders[r.platform_id].index(min(allbuilders[r.platform_id], - key=lambda x:x.queue.qsize())) - logger.info("Assign building of " + r.name + " to " + allbuilders[r.platform_id][idx].name) - allbuilders[r.platform_id][idx].queue.put(job) - - self.send_response(HTTPStatus.OK.value) - self.end_headers() - - except Exception as e: - sendEmailAdmins("Receive new tag failed", str(e)) - logger.error("Receive new tag failed: ", str(e)) - session.rollback() - self.send_response(HTTPStatus.INTERNAL_SERVER_ERROR.value) - self.end_headers() - finally: - session.close() - -def run(address, port, server_class=HTTPServer, handler_class=Server): - logger.info('Starting...') - server_address = (address, port) - httpd = server_class(server_address, handler_class) - try: - httpd.serve_forever() - except KeyboardInterrupt: - pass - httpd.server_close() - logger.info('Stopping...') - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument("--db", type=str, help='Database URI to connect to', required=True) - parser.add_argument('--bind', type=str, default='localhost', help='IP Address or hostname to bind to') - parser.add_argument('--port', type=int, default=443, help='Port to listen to') - parser.add_argument("--store", type=str, default='/scratch/build/files-store/', help='Directory where store produced binaries') - parser.add_argument("--repo", type=str, default='/scratch/build/repositories/', help='Directory where checkout git repositories') - parser.add_argument("--smtpserver", type=str, default="smtp", help='Hostname of the SMTP server') - parser.add_argument("--smtpsender", type=str, default="noreply", help='Email sender') - parser.add_argument("--smtpdomain", type=str, default="elettra.eu", help='Email domain') - args = parser.parse_args() - - print("Start inau-dispatcher using", args.db, "on interface", args.bind, "and port", - args.port, "file store directory", args.store, "repositories clone directory", args.repo, - "SMTP server", args.smtpserver, "SMTP sender", args.smtpsender, "SMTP domain", args.smtpdomain) - - if os.getpgrp() == os.tcgetpgrp(sys.stdout.fileno()): - # Executed in foreground so redirect log to terminal and enable SQL echoing (Development) - logging.basicConfig(level=logging.INFO) - engine = create_engine(args.db, pool_pre_ping=True, echo=True) - else: - # Executed in background so redirect log to syslog and disable SQL echoing (Production) - syslog_handler = logging.handlers.SysLogHandler(address='/dev/log') - logging.basicConfig(level=logging.INFO, handlers=[syslog_handler]) - engine = create_engine(args.db, pool_pre_ping=True, echo=False) - logger = logging.getLogger('inau-dispatcher') - - Session.configure(bind=engine) - - reconcile() - signal.signal(signal.SIGHUP, signalHandler) - - if args.bind: - run(args.bind,args.port) diff --git a/inau.py b/inau.py deleted file mode 100644 index ee921d46fc7deb1faae839c98d55b26436933fdc..0000000000000000000000000000000000000000 --- a/inau.py +++ /dev/null @@ -1,1361 +0,0 @@ -import logging -import argparse -import datetime -import time -import ldap -import base64 -import json -import paramiko -import shutil -import hashlib -import os -import git -import re -from enum import Enum, IntEnum -from werkzeug.exceptions import HTTPException, Unauthorized, Forbidden, InternalServerError, MethodNotAllowed, BadRequest, UnprocessableEntity, NotFound -from smtplib import SMTP -from email.mime.text import MIMEText -from flask import Flask, request, make_response, got_request_exception, render_template -from flask_restful import Resource, Api, reqparse, fields, marshal_with -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy import func -from sqlalchemy.orm import joinedload -from sqlalchemy.exc import IntegrityError - -# Create Flask, Api and SQLAlchemy object -app = Flask(__name__) -v2 = Api(app, prefix='/v2') # default_mediatype doesn't take "Accept: */*" into account -db = SQLAlchemy() - -parser = argparse.ArgumentParser() -parser.add_argument("--db", required=True) -parser.add_argument("--smtpdomain", default="elettra.eu") -parser.add_argument("--smtpserver", default="smtp.elettra.eu") -parser.add_argument("--smtpsender", default="noreply") -parser.add_argument("--store", default="/scratch/build/files-store/") -parser.add_argument("--repo", default="/scratch/build/repositories/") -parser.add_argument("--ldap", default="ldaps://abook.elettra.eu:636") -parser.add_argument("--port", default="443") -args = parser.parse_args() - -class Users(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(255), unique=True, nullable=False) - admin = db.Column(db.Boolean, nullable=False) - -class Facilities(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(255), unique=True, nullable=False) - -class Distributions(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(255), nullable=False) - version = db.Column(db.String(255), nullable=False) - -class Architectures(db.Model): - id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(255), unique=True, nullable=False) - -class Platforms(db.Model): - id = db.Column(db.Integer, primary_key=True) - distribution_id = db.Column(db.Integer, db.ForeignKey('distributions.id'), nullable=False) - architecture_id = db.Column(db.Integer, db.ForeignKey('architectures.id'), nullable=False) - distribution = db.relationship('Distributions', lazy=True, backref=db.backref('platforms', lazy=True)) - architecture = db.relationship('Architectures', lazy=True, backref=db.backref('platforms', lazy=True)) - -class Providers(db.Model): - id = db.Column(db.Integer, primary_key=True) - url = db.Column(db.String(255), unique=True, nullable=False) - -class Repositories(db.Model): - id = db.Column(db.Integer, primary_key=True) - provider_id = db.Column(db.Integer, db.ForeignKey('providers.id'), nullable=False) - platform_id = db.Column(db.Integer, db.ForeignKey('platforms.id'), nullable=False) - type = db.Column(db.Integer, nullable=False) - name = db.Column(db.String(255), unique=True, nullable=False) - destination = db.Column(db.String(255), nullable=False) - provider = db.relationship('Providers', lazy=True, backref=db.backref('repositories', lazy=True)) - platform = db.relationship('Platforms', lazy=True, backref=db.backref('repositories', lazy=True)) - enabled = db.Column(db.Boolean, default=True, nullable=False) - -class Servers(db.Model): - id = db.Column(db.Integer, primary_key=True) - platform_id = db.Column(db.Integer, db.ForeignKey('platforms.id'), nullable=False) - name = db.Column(db.String(255), nullable=False) - prefix = db.Column(db.String(255), nullable=False) - platform = db.relationship('Platforms', lazy=True, backref=db.backref('servers', lazy=True)) - -class Hosts(db.Model): - id = db.Column(db.Integer, primary_key=True) - facility_id = db.Column(db.Integer, db.ForeignKey('facilities.id'), nullable=False) - server_id = db.Column(db.Integer, db.ForeignKey('servers.id'), nullable=False) - name = db.Column(db.String(255), unique=True, nullable=False) - facility = db.relationship('Facilities', lazy=True, backref=db.backref('hosts', lazy=True)) - server = db.relationship('Servers', lazy=True, backref=db.backref('hosts', lazy=True)) - -class Builders(db.Model): - id = db.Column(db.Integer, primary_key=True) - platform_id = db.Column(db.Integer, db.ForeignKey('platforms.id'), nullable=False) - name = db.Column(db.String(255), unique=False, nullable=False) - platform = db.relationship('Platforms', lazy=True, backref=db.backref('builders', lazy=True)) - environment = db.Column(db.String(255), unique=False, nullable=True) - -class Artifacts(db.Model): - id = db.Column(db.Integer, primary_key=True) - build_id = db.Column(db.Integer, db.ForeignKey('builds.id'), nullable=False) - hash = db.Column(db.String(255), nullable=True) - filename = db.Column(db.String(255), nullable=False) - symlink_target = db.Column(db.String(255), nullable=True) - build = db.relationship('Builds', lazy=True, backref=db.backref('artifacts', lazy=True)) - -class Builds(db.Model): - id = db.Column(db.Integer, primary_key=True) - repository_id = db.Column(db.Integer, db.ForeignKey('repositories.id'), nullable=False) - platform_id = db.Column(db.Integer, db.ForeignKey('platforms.id'), nullable=False) - tag = db.Column(db.String(255), nullable=False) - date = db.Column(db.DateTime, default=datetime.datetime.now, nullable=False) - status = db.Column(db.Integer, nullable=True) - output = db.Column(db.Text, nullable=True) - repository = db.relationship('Repositories', lazy=True, backref=db.backref('builds', lazy=True)) -# platform = db.relationship('Platforms', lazy=True, backref=db.backref('repositories', lazy=True)) - -class Installations(db.Model): - id = db.Column(db.Integer, primary_key=True) - host_id = db.Column(db.Integer, db.ForeignKey('hosts.id'), nullable=False) - user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) - build_id = db.Column(db.Integer, db.ForeignKey('builds.id'), nullable=False) - type = db.Column(db.Integer, nullable=False) - date = db.Column(db.DateTime, nullable=False) - host = db.relationship('Hosts', lazy=True, backref=db.backref('installations', lazy=True)) - user = db.relationship('Users', lazy=True, backref=db.backref('installations', lazy=True)) - build = db.relationship('Builds', lazy=True, backref=db.backref('installations', lazy=True)) - -class AuthenticationType(Enum): - USER = 0, - ADMIN = 1 - -def authenticate(authtype, request): - auth = ldap.initialize(app.config['LDAP_URL'], bytes_mode=False) - if request.headers.get('Authorization') == None: - print("Missing authorization header") - raise Unauthorized() - split = request.headers.get('Authorization').strip().split(' ') - username, password = base64.b64decode(split[1]).decode().split(':', 1) - user = Users.query.filter(Users.name == username).first() - if user is None: - print("User isn't enabled") - raise Forbidden() - if authtype == AuthenticationType.ADMIN and user.admin is False: - print("Admin authentication type is required") - raise Forbidden() - try: - auth.simple_bind_s("uid=" + username +",ou=people,dc=elettra,dc=eu", password) - auth.unbind_s() - except Exception as e: - print("LDAP issue: ", e) - raise Forbidden() - return username - -@v2.representation('application/json') -def output_json(data, code, headers=None): - resp = make_response(json.dumps(data), code) - resp.headers.extend(headers or {}) - return resp - -@v2.representation('text/plain') -def output_plain(data, code, headers=None): - retval = "" - highest = {} - - if isinstance(data, dict): - try: - message = data['message'] - if isinstance(message, dict): - for k, v in message.items(): - retval += "message: " + v + "\n" - else: # str - retval += "message: " + message + "\n"; - except KeyError: - data = [data] - - if isinstance(data, list): - for item in data: - for k, v in item.items(): - highest.update({ k : max(highest.get(k, 0), len(k), len(str(v))) }) - - if len(data): - columns = "" - for k, v in data[0].items(): - if len(columns) != 0: - columns += " " - columns += k.ljust(highest[k]) - retval += columns + "\n" - - line = "" - for k, v in data[0].items(): - if len(line) != 0: - line += "--" - line += "-" * highest[k] - retval += line + "\n" - - for item in data: - rows = "" - for k, v in item.items(): - if len(rows) != 0: - rows += " " - rows += str(v).ljust(highest[k]) - retval += rows + "\n" - - retval = retval[:-1] - - resp = make_response(retval, code) - resp.headers.extend(headers or {}) - return resp - -def non_empty_string(s): - if not s: - raise ValueError("Must not be empty string") - return s - -def execSyncedCommand(sshClient, cmd): - _, stdout, stderr = sshClient.exec_command(cmd) - exitStatus = stdout.channel.recv_exit_status() - return stdout.read().decode('utf-8'), stderr.read().decode('utf-8'), exitStatus - -def sendEmail(to, subject, body): - if args.port != "443": - print(subject, str(body)) - else: - with SMTP(host=app.config['MAIL_SERVER'], port=25) as smtpClient: - sender = app.config['MAIL_DEFAULT_SENDER'] - receivers = [ to ] - msg = MIMEText(str(body)) - msg['Subject'] = "INAU. " + subject - msg['From'] = sender - msg['To'] = to[0] - smtpClient.sendmail(from_addr=sender, to_addrs=receivers, - msg=msg.as_string()) - -def sendEmailAdmins(subject, body): - for admin in Users.query.filter(Users.admin == True).all(): - sendEmail([admin.name + "@" + app.config['MAIL_DOMAIN']], subject, body) - -def log_exception(sender, exception, **extra): - if isinstance(exception, MethodNotAllowed) or isinstance(exception, BadRequest) or \ - isinstance(exception, UnprocessableEntity) or isinstance(exception, Forbidden): - return - sendEmailAdmins(str(sender), str(exception)) - -got_request_exception.connect(log_exception, app) - -class InstallationType(IntEnum): - GLOBAL = 0, - FACILITY = 1, - HOST = 2 - -class RepositoryType(IntEnum): - cplusplus = 0, - python = 1, - configuration = 2, - shellscript = 3, - library = 4 - -def install(username, reponame, tag, destinations, itype): - now = datetime.datetime.now() - retval = [] - user = Users.query.filter(Users.name == username) \ - .first_or_404(description='User not found') - if not destinations.items(): - raise NotFound - for server, hosts in destinations.items(): - repository = Repositories.query.with_parent(server.platform) \ - .filter(Repositories.name == reponame) \ - .first_or_404(description='Repository not found. Check syntax.') - build = Builds.query.with_parent(repository).filter(Builds.tag == tag, Builds.status == 0) \ - .order_by(Builds.id.desc()) \ - .first_or_404("Requested build not available. Check annotated tag.") - try: - with paramiko.SSHClient() as sshClient: - sshClient.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - print("Connect to " + server.name + "...") - sshClient.connect(hostname=server.name, port=22, username="root", - key_filename="/home/inau/.ssh/id_rsa.pub") - with sshClient.open_sftp() as sftpClient: - artifacts = [] - for host in hosts: - facility = host.facility.name - for artifact in Artifacts.query.with_parent(build).all(): - if repository.type == RepositoryType.library and facility != "development": - if re.search("^(lib/|bin/)", artifact.filename): - if re.search("^(lib/cmake|lib/pkgconfig)", artifact.filename): - pass - else: - artifacts.append(artifact) - else: - pass - else: - artifacts.append(artifact) - for artifact in artifacts: - print("Install", artifact.filename, "to", server.name, "...") - if artifact.hash is not None: - with open(app.config['FILES_STORE_DIR'] + artifact.hash[0:2] + "/" + artifact.hash[2:4] + "/" + artifact.hash, "rb") as binaryFile: - sftpClient.putfo(binaryFile, "/tmp/" + artifact.hash) - filemode = "755" - if repository.type == RepositoryType.configuration: - filemode = "644" - # repository.type == RepositoryType.library have to provide files with the right permissions - if itype == InstallationType.GLOBAL or itype == InstallationType.FACILITY: - if not repository.type == RepositoryType.library: - cmd = "rm " + server.prefix + "/site/*/" + repository.destination + artifact.filename - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "install -d " + server.prefix + repository.destination \ - + os.path.dirname(artifact.filename) - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "install -m" + filemode + " /tmp/" + artifact.hash + " " \ - + server.prefix + repository.destination + artifact.filename - _, stderr, exitStatus = execSyncedCommand(sshClient, cmd) - else: - cmd = "rm " + server.prefix + "/site/*/" + artifact.filename - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "install -d " + server.prefix + os.path.dirname(artifact.filename) - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "install " + "/tmp/" + artifact.hash + " " \ - + server.prefix + artifact.filename - _, stderr, exitStatus = execSyncedCommand(sshClient, cmd) - if exitStatus != 0: - raise Exception(stderr) - else: # InstallationType.HOST - for host in hosts: - if not repository.type == RepositoryType.library: - cmd = "install -d " + server.prefix + "/site/" + host.name + "/" \ - + repository.destination + os.path.dirname(artifact.filename) - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "install -m" + filemode + " /tmp/" + artifact.hash + " " + server.prefix \ - + "/site/" + host.name + "/" + repository.destination + artifact.filename - _, stderr, exitStatus = execSyncedCommand(sshClient, cmd) - else: - cmd = "install -d " + server.prefix + "/site/" + host.name + "/" \ - + os.path.dirname(artifact.filename) - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "install " + "/tmp/" + artifact.hash + " " + server.prefix \ - + "/site/" + host.name + "/" + artifact.filename - _, stderr, exitStatus = execSyncedCommand(sshClient, cmd) - if exitStatus != 0: - raise Exception(stderr) - else: - if itype == InstallationType.GLOBAL or itype == InstallationType.FACILITY: - cmd = "rm " + server.prefix + "/site/*/" + artifact.filename - _, _, _ = execSyncedCommand(sshClient, cmd) - cmd = "ln -sfrn " + server.prefix + artifact.symlink_target + " " + server.prefix + artifact.filename - else: - cmd = "ln -sfrn " + server.prefix + "/site/" + host.name + "/" + artifact.symlink_target \ - + " " + server.prefix + "/site/" + host.name + "/" + artifact.filename - _, stderr, exitStatus = execSyncedCommand(sshClient, cmd) - if exitStatus != 0: - raise Exception(stderr) - except Exception as e: - raise InternalServerError(description=str(e)) - - for host in hosts: - installation = Installations(user=user, host=host, build=build, date=now, type=int(itype)) - db.session.add(installation) - db.session.commit() - - retval.append({ 'facility': host.facility.name, 'host': host.name, - 'repository': repository.name,'tag': build.tag, 'date': installation.date, - 'author': user.name }) - return retval - -class CSHandler(Resource): - def get(self): - return [{ 'subpath': 'users'}, - { 'subpath': 'distributions'}, - { 'subpath': 'architectures'}, - { 'subpath': 'platforms'}, - { 'subpath': 'builders'}, - { 'subpath': 'servers'}, - { 'subpath': 'providers'}, - { 'subpath': 'repositories'}, - { 'subpath': 'facilities' }] - -users_fields = { 'name': fields.String() } -class UsersHandler(Resource): - @marshal_with(users_fields) - def get(self): - users = Users.query.all() - return users, 200 if users else 204 - @marshal_with(users_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=alessio.bogani)') - args = parser.parse_args(strict=True) - args = parser.parse_args() - authenticate(AuthenticationType.ADMIN, request) - try: - user = Users(name = args['name'], admin = False) - db.session.add(user) - db.session.commit() - return user, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class UserHandler(Resource): - @marshal_with(users_fields) - def put(self, username): - user = Users.query.filter(Users.name == username).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=user.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=alessio.bogani)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - user.name = args['name'] - db.session.commit() - return user, 201 - def delete(self, username): - user = Users.query.filter(Users.name == username).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(user) - db.session.commit() - return {}, 204 - -architectures_fields = { 'name': fields.String() } -class ArchitecturesHandler(Resource): - @marshal_with(architectures_fields) - def get(self): - architectures = Architectures.query.all() - return architectures, 200 if architectures else 204 - @marshal_with(architectures_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - try: - arch = Architectures(name = args['name']) - db.session.add(arch) - db.session.commit() - return arch, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class ArchitectureHandler(Resource): - @marshal_with(architectures_fields) - def put(self, archname): - arch = Architectures.query.filter(Architectures.name == archname).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=arch.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - arch.name = args['name'] - db.session.commit() - return arch, 201 - def delete(self, archname): - arch = Architectures.query.filter(Architectures.name == archname).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(arch) - db.session.commit() - return {}, 204 - -distributions_fields = { 'id': fields.Integer(), - 'name': fields.String(), 'version': fields.String() } -class DistributionsHandler(Resource): - @marshal_with(distributions_fields) - def get(self): - distributions = Distributions.query.all() - return distributions, 200 if distributions else 204 - @marshal_with(distributions_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=Ubuntu)') - parser.add_argument('version', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - try: - distro = Distributions(name = args['name'], version = args['version']) - db.session.add(distro) - db.session.commit() - return distro, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class DistributionHandler(Resource): - @marshal_with(distributions_fields) - def put(self, distroid): - distro = Distributions.query.filter(Distributions.id == distroid).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=distro.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=Ubuntu)') - parser.add_argument('version', default=distro.version, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro.name = args['name'] - distro.version = args['version'] - db.session.commit() - return distro, 201 - def delete(self, distroid): - distro = Distributions.query.filter(Distributions.id == distroid).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(distro) - db.session.commit() - return {}, 204 - -platforms_fields = { 'id': fields.Integer, - 'distribution': fields.String(attribute='distribution.name'), - 'version': fields.String(attribute='distribution.version'), - 'architecture': fields.String(attribute='architecture.name') } -class PlatformsHandler(Resource): - @marshal_with(platforms_fields) - def get(self): - platforms = Platforms.query.all() - return platforms, 200 if platforms else 204 - @marshal_with(platforms_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('distribution', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - try: - plat = Platforms(architecture_id = arch.id, distribution_id = distro.id) - db.session.add(plat) - db.session.commit() - return plat, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class PlatformHandler(Resource): - @marshal_with(platforms_fields) - def put(self, platid): - plat = Platforms.query.filter(Platforms.id == platid).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('distribution', default=plat.distribution.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', default=plat.distribution.version, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', default=plat.architecture.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat.distribution_id = distro.id - plat.architecture_id = arch.id - db.session.commit() - return plat, 201 - def delete(self, platid): - plat = Platforms.query.filter(Platforms.id == platid).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(plat) - db.session.commit() - return {}, 204 - -builders_fields = { 'name': fields.String(), - 'distribution': fields.String(attribute='platform.distribution.name'), - 'version': fields.String(attribute='platform.distribution.version'), - 'architecture': fields.String(attribute='platform.architecture.name') } -class BuildersHandler(Resource): - @marshal_with(builders_fields) - def get(self): - builders = Builders.query.all() - return builders, 200 if builders else 204 - @marshal_with(builders_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=anguilla)') - parser.add_argument('distribution', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat = Platforms.query.with_parent(distro).with_parent(arch) \ - .first_or_404(description="Platform doesn't exist") - try: - builder = Builders(name = args['name'], platform = plat) - db.session.add(builder) - db.session.commit() - return builder, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class BuilderHandler(Resource): - @marshal_with(builders_fields) - def put(self, buildername): - builder = Builders.query.filter(Builders.name == buildername).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=builder.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=anguilla)') - parser.add_argument('distribution', default=builder.platform.distribution.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', default=builder.platform.distribution.version, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', default=builder.platform.architecture.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat = Platforms.query.with_parent(distro).with_parent(arch) \ - .first_or_404(description="Platform doesn't exist") - builder.name = args['name'] - builder.platform = plat - db.session.commit() - return builder, 201 -# def delete(self, buildername): -# builder = Builders.query.filter(Builders.name == buildername).first_or_404() -# authenticate(AuthenticationType.ADMIN, request) -# db.session.delete(builder) -# db.session.commit() -# return {}, 204 - -servers_fields = { 'name': fields.String(), 'prefix': fields.String(), - 'distribution': fields.String(attribute='platform.distribution.name'), - 'version': fields.String(attribute='platform.distribution.version'), - 'architecture': fields.String(attribute='platform.architecture.name') } -class ServersHandler(Resource): - @marshal_with(servers_fields) - def get(self): - servers = Servers.query.all() - return servers, 200 if servers else 204 - @marshal_with(servers_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=srv-net-srf)') - parser.add_argument('prefix', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. prefix=/runtime/)') - parser.add_argument('distribution', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat = Platforms.query.with_parent(distro).with_parent(arch) \ - .first_or_404(description="Platform doesn't exist") - try: - server = Servers(name = args['name'], prefix = args['prefix'], platform = plat) - db.session.add(server) - db.session.commit() - return server, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class ServerHandler(Resource): - @marshal_with(servers_fields) - def put(self, servername): - server = Servers.query.filter(Servers.name == servername).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=server.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=srv-net-srf)') - parser.add_argument('prefix', default=server.prefix, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. prefix=/runtime/)') - parser.add_argument('distribution', default=server.platform.distribution.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', default=server.platform.distribution.version, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', default=server.platform.architecture.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat = Platforms.query.with_parent(distro).with_parent(arch) \ - .first_or_404(description="Platform doesn't exist") - server.name = args['name'] - server.prefix = args['prefix'] - server.platform = plat - db.session.commit() - return server, 201 - def delete(self, servername): - server = Servers.query.filter(Servers.name == servername).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(server) - db.session.commit() - return {}, 204 - -providers_fields = { 'id': fields.Integer(), 'url': fields.String() } -class ProvidersHandler(Resource): - @marshal_with(providers_fields) - def get(self): - providers = Providers.query.all() - return providers, 200 if providers else 204 - @marshal_with(providers_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('url', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. url=ssh://git@gitlab.elettra.eu:/cs/ds/)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - try: - provider = Providers(url = args['url']) - db.session.add(provider) - db.session.commit() - return provider, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class ProviderHandler(Resource): - @marshal_with(providers_fields) - def put(self, providerid): - provider = Providers.query.filter(Providers.id == providerid).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('url', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. url=ssh://git@gitlab.elettra.eu:/cs/ds/)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - provider.url = args['url'] - db.session.commit() - return provider, 201 - def delete(self, providerid): - provider = Providers.query.filter(Providers.id == providerid).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(provider) - db.session.commit() - return {}, 204 - -class RepositoryTypeItem(fields.Raw): - def format(self, value): - if value == RepositoryType.cplusplus: - return 'cplusplus' - elif value == RepositoryType.python: - return 'python' - elif value == RepositoryType.shellscript: - return 'shellscript' - elif value == RepositoryType.library: - return 'library' - else: # value == RepositoryType.configuration - return 'configuration' - -repositories_fields = { 'id': fields.Integer(), 'name': fields.String(), - 'provider': fields.String(attribute='provider.url'), - 'distribution': fields.String(attribute='platform.distribution.name'), - 'version': fields.String(attribute='platform.distribution.version'), - 'architecture': fields.String(attribute='platform.architecture.name'), - 'type': RepositoryTypeItem(), 'destination': fields.String(), - 'enabled': fields.Boolean() } -class RepositoriesHandler(Resource): - @marshal_with(repositories_fields) - def get(self): - repositories = Repositories.query.all() - return repositories, 200 if repositories else 204 - @marshal_with(repositories_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=cs/ds/fake)') - parser.add_argument('provider', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. provider=ssh://git@gitlab.elettra.eu:/cs/ds/)') - parser.add_argument('distribution', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. architecture=ppc7400)') - parser.add_argument('type', required=True, trim=True, nullable=False, - choices=['cplusplus', 'python', 'shellscript', 'configuration', 'library'], type=non_empty_string, - help='{error_msg} (e.g. type=cplusplus)') - parser.add_argument('destination', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. destination=/bin/)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat = Platforms.query.with_parent(distro).with_parent(arch) \ - .first_or_404(description="Platform doesn't exist") - prov = Providers.query.filter(Providers.url == args['provider']) \ - .first_or_404(description="Provider doesn't exist") - try: - repo = Repositories(name = args['name'], provider = prov, platform = plat, - type = RepositoryType[args['type']].value, destination=args['destination']) - db.session.add(repo) - db.session.commit() - return repo, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class RepositoryHandler(Resource): - @marshal_with(repositories_fields) - def put(self, repositoryid): - repo = Repositories.query.filter(Repositories.id == repositoryid).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=repo.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=cs/ds/fake)') - parser.add_argument('provider', default=repo.provider.url, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. provider=ssh://git@gitlab.elettra.eu:/cs/ds/)') - parser.add_argument('distribution', default=repo.platform.distribution.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. distribution=Ubuntu)') - parser.add_argument('version', default=repo.platform.distribution.version, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. version=18.04)') - parser.add_argument('architecture', default=repo.platform.architecture.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. architecture=ppc)') - parser.add_argument('type', default=RepositoryType(repo.type).name, trim=True, nullable=False, - choices=['cplusplus', 'python', 'shellscript', 'configuration', 'library'], type=non_empty_string, - help='{error_msg} (e.g. type=cplusplus)') - parser.add_argument('destination', default=repo.destination, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. destination=/bin/)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - distro = Distributions.query.filter(Distributions.name == args['distribution'], - Distributions.version == args['version']) \ - .first_or_404(description="Distribution doesn't exist") - arch = Architectures.query.filter(Architectures.name == args['architecture']) \ - .first_or_404(description="Architecture doesn't exist") - plat = Platforms.query.with_parent(distro).with_parent(arch) \ - .first_or_404(description="Platform doesn't exist") - prov = Providers.query.filter(Providers.url == args['provider']) \ - .first_or_404(description="Provider doesn't exist") - repo.name = args['name'] - repo.provider = prov - repo.platform = plat - repo.type = RepositoryType[args['type']].value - repo.destination = args['destination'] - db.session.commit() - return repo, 201 - def delete(self, repositoryid): - repo = Repositories.query.filter(Repositories.id == repositoryid).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(repo) - db.session.commit() - return {}, 204 - -facilities_fields = { 'name': fields.String() } -class FacilitiesHandler(Resource): - @marshal_with(facilities_fields) - def get(self): - facilities = Facilities.query.all() - return facilities, 200 if facilities else 204 - @marshal_with(facilities_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=fermi)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - try: - fac = Facilities(name = args['name']) - db.session.add(fac) - db.session.commit() - return fac, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description='Integrity error') - -class FacilityHandler(Resource): - @marshal_with(facilities_fields) - def put(self, facilityname): - fac = Facilities.query.filter(Facilities.name == facilityname).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default.fac.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=fermi)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - fac.name = args['name'] - db.session.commit() - return fac, 201 - def delete(self, facilityname): - fac = Facilities.query.filter(Facilities.name == facilityname).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(fac) - db.session.commit() - return {}, 204 - -hosts_fields = { 'name': fields.String(), - 'server': fields.String(attribute='server.name'), - 'facility': fields.String(attribute='facility.name') } -class HostsHandler(Resource): - @marshal_with(hosts_fields) - def get(self, facilityname): - fac = Facilities.query.filter(Facilities.name == facilityname).first_or_404() - hosts = Hosts.query.with_parent(fac).all() - return hosts, 200 if hosts else 204 - @marshal_with(hosts_fields) - def post(self, facilityname): - parser = reqparse.RequestParser() - parser.add_argument('name', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=ec-sl-slpsr-01)') - parser.add_argument('server', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. server=srv-net-srf)') - parser.add_argument('prefix', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. prefix=/runtime/)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - fac = Facilities.query.filter(Facilities.name == facilityname) \ - .first_or_404(description="Facility doesn't exist") - srv = Servers.query.filter(Servers.name == args['server'], - Servers.prefix == args['prefix']) \ - .first_or_404(description="Server doesn't exist") - try: - host = Hosts(name = args['name'], server = srv, facility = fac) - db.session.add(host) - db.session.commit() - return host, 201 - except IntegrityError: - db.session.rollback() - raise UnprocessableEntity(description="Integrity error") - -class HostHandler(Resource): - @marshal_with(hosts_fields) - def put(self, facilityname, hostname): - host = Hosts.query.filter(Hosts.name == hostname).first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('name', default=host.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. name=ec-sl-slpsr-01)') - parser.add_argument('server', default=host.server.name, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. server=srv-net-srf)') - parser.add_argument('prefix', default=host.server.prefix, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. prefix=/runtime/)') - parser.add_argument('facility', default=host.facility.name, trim=True, - nullable=False, type=non_empty_string, help='{error_msg} (e.g. fermi)') - args = parser.parse_args(strict=True) - authenticate(AuthenticationType.ADMIN, request) - fac = Facilities.query.filter(Facilities.name == args['facility']) \ - .first_or_404(description="Facility doesn't exist") - srv = Servers.query.filter(Servers.name == args['server'], - Servers.prefix == args['prefix']) \ - .first_or_404(description="Server doesn't exist") - host.name = args['name'] - host.server = srv - host.facility = fac - db.session.commit() - return host, 201 - def delete(self, facilityname, hostname): - host = Hosts.query.filter(Hosts.name == hostname).first_or_404() - authenticate(AuthenticationType.ADMIN, request) - db.session.delete(host) - db.session.commit() - return {}, 204 - - -#files_fields = { 'filename': fields.String() } -#class FilesHandler(Resource): -# @marshal_with(files_fields) -# def get(self, facilityname, hostname): -# host = Hosts.query.join('facility').\ -# filter(Facilities.name == facilityname, -# Hosts.name == hostname).\ -# first_or_404() -# LatestInstallations = db.session.query(Installations)\ -# .with_entities(Repositories.id, Installations.host_id,\ -# func.max(Installations.id).label('installation_id'))\ -# .select_from(Installations)\ -# .join(Builds).join(Repositories)\ -# .group_by(Repositories.id, Installations.host_id)\ -# .subquery() -# retval = [] -# for artifact in Builds.query.join('installations').join('artifacts').\ -# join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ -# with_entities(Artifacts).filter(Installations.host == host).all(): -# retval.append({ 'filename' : artifact.filename }) -# return retval, 200 if retval else 204 -# -#file_fields = { 'filename': fields.String(), 'hash': fields.String() } -#class FileHandler(Resource): -# @marshal_with(file_fields) -# def get(self, facilityname, hostname, filename): -# host = Hosts.query.join('facility').\ -# filter(Facilities.name == facilityname, -# Hosts.name == hostname).\ -# first_or_404() -# LatestInstallations = db.session.query(Installations)\ -# .with_entities(Repositories.id, Installations.host_id,\ -# func.max(Installations.id).label('installation_id'))\ -# .select_from(Installations)\ -# .join(Builds).join(Repositories)\ -# .group_by(Repositories.id, Installations.host_id)\ -# .subquery() -# artifact = Builds.query.\ -# join('installations').\ -# join('artifacts').\ -# join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ -# with_entities(Artifacts).\ -# filter(Artifacts.filename == filename, Installations.host == host).\ -# first_or_404() -# return { 'filename': artifact.filename, 'hash': artifact.hash } - -mode_parser = reqparse.RequestParser() -mode_parser.add_argument('mode', type=str, default='status', required=False, - choices=['status', 'diff', 'history'], location='args') - -cs_installations_fields = { 'facility': fields.String(), - 'host': fields.String(), 'repository': fields.String(), - 'tag': fields.String(), 'date': fields.DateTime(), - 'author': fields.String() } -class CSInstallationsHandler(Resource): - @marshal_with(cs_installations_fields) - def get(self): - args = mode_parser.parse_args(strict=True) - LatestInstallations = db.session.query(Installations)\ - .with_entities(Repositories.id, Installations.host_id,\ - func.max(Installations.id).label('installation_id'))\ - .select_from(Installations)\ - .join(Builds).join(Repositories)\ - .group_by(Repositories.id, Installations.host_id)\ - .subquery() - if args['mode'] == 'status': - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True).\ - joinedload('facility', innerjoin=True)).\ - join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ - order_by(Installations.date.desc()).all() - elif args['mode'] == 'diff': - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True).\ - joinedload('facility', innerjoin=True)).\ - join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ - filter(Installations.type != int(InstallationType.GLOBAL)).\ - order_by(Installations.date.desc()).all() - else: # history - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True).\ - joinedload('facility', innerjoin=True)).\ - order_by(Installations.date.desc()).all() - retval = [] - for installation in installations: - retval.append({ 'facility': installation.host.facility.name, - 'host': installation.host.name, - 'repository': installation.build.repository.name, - 'tag': installation.build.tag, 'date': installation.date, - 'author': installation.user.name }) - return retval, 200 if len(retval) else 204 - @marshal_with(cs_installations_fields) - def post(self): - parser = reqparse.RequestParser() - parser.add_argument('repository', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. repository=fake)') - parser.add_argument('tag', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. tag=0.0.4)') - args = parser.parse_args(strict=True) - username = authenticate(AuthenticationType.USER, request) - destinations = {} - for repository in Repositories.query.\ - filter(Repositories.name == args['repository']).\ - filter(Repositories.enabled == 1).\ - all(): - for server in repository.platform.servers: - for host in server.hosts: - try: - destinations[host.server].add(host) - except KeyError: - destinations[host.server] = {host} - return install(username, args['repository'], args['tag'], - destinations, InstallationType.GLOBAL) - -facility_installations_fields = { 'host': fields.String(), - 'repository': fields.String(), 'tag': fields.String(), - 'date': fields.DateTime(), 'author': fields.String() } -class FacilityInstallationsHandler(Resource): - @marshal_with(facility_installations_fields) - def get(self, facilityname): - facility = Facilities.query.\ - filter(Facilities.name == facilityname).\ - first_or_404() - args = mode_parser.parse_args(strict=True) - LatestInstallations = db.session.query(Installations)\ - .with_entities(Repositories.id, Installations.host_id,\ - func.max(Installations.id).label('installation_id'))\ - .select_from(Installations)\ - .join(Builds).join(Repositories)\ - .group_by(Repositories.id, Installations.host_id)\ - .subquery() - if args['mode'] == 'status': - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True)).\ - join('host').\ - join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ - filter(Hosts.facility == facility).\ - order_by(Installations.date.desc()).all() - elif args['mode'] == 'diff': - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True)).\ - join('host').\ - join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ - filter(Hosts.facility == facility, - Installations.type == int(InstallationType.HOST)).\ - order_by(Installations.date.desc()).all() - else: # history - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True)).\ - join('host').\ - filter(Hosts.facility == facility).\ - order_by(Installations.date.desc()).all() - retval = [] - for installation in installations: - retval.append({ 'host': installation.host.name, - 'repository': installation.build.repository.name, - 'tag': installation.build.tag, 'date': installation.date, - 'author': installation.user.name }) - return retval, 200 if len(retval) else 204 - @marshal_with(facility_installations_fields) - def post(self, facilityname): - facility = Facilities.query.filter(Facilities.name == facilityname) \ - .first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('repository', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. repository=fake)') - parser.add_argument('tag', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. tag=0.0.4)') - args = parser.parse_args(strict=True) - username = authenticate(AuthenticationType.USER, request) - destinations = {} - for repository in Repositories.query.\ - filter(Repositories.name == args['repository']).\ - filter(Repositories.enabled == 1).\ - all(): - for server in repository.platform.servers: - for host in server.hosts: - if host.facility_id != facility.id: - continue - try: - destinations[host.server].add(host) - except KeyError: - destinations[host.server] = {host} - return install(username, args['repository'], args['tag'], - destinations, InstallationType.FACILITY) - -host_installations_fields = { 'repository': fields.String(), - 'tag': fields.String(), 'date': fields.DateTime(), - 'author': fields.String() } -class HostInstallationsHandler(Resource): - @marshal_with(host_installations_fields) - def get(self, facilityname, hostname): - host = Hosts.query.join('facility').\ - filter(Facilities.name == facilityname, - Hosts.name == hostname).\ - first_or_404() - args = mode_parser.parse_args(strict=True) - LatestInstallations = db.session.query(Installations)\ - .with_entities(Repositories.id, Installations.host_id,\ - func.max(Installations.id).label('installation_id'))\ - .select_from(Installations)\ - .join(Builds).join(Repositories)\ - .group_by(Repositories.id, Installations.host_id)\ - .subquery() - if args['mode'] == 'status': - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True)).\ - join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ - filter(Installations.host == host).\ - order_by(Installations.date.desc()).all() - elif args['mode'] == 'diff': - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True)).\ - join(LatestInstallations, Installations.id == LatestInstallations.c.installation_id).\ - filter(Installations.host == host, - Installations.type == int(InstallationType.HOST)).\ - order_by(Installations.date.desc()).all() - else: # history - installations = Installations.query.options( - joinedload('user', innerjoin=True),\ - joinedload('build', innerjoin=True).\ - joinedload('repository', innerjoin=True), - joinedload('host', innerjoin=True)).\ - filter(Installations.host == host).\ - order_by(Installations.date.desc()).all() - retval = [] - for installation in installations: - retval.append({ 'repository': installation.build.repository.name, - 'tag': installation.build.tag, 'date': installation.date, - 'author': installation.user.name }) - return retval, 200 if len(retval) else 204 - @marshal_with(host_installations_fields) - def post(self, facilityname, hostname): - host = Hosts.query.options(joinedload('facility', innerjoin=True)) \ - .filter(Facilities.name == facilityname, Hosts.name == hostname) \ - .first_or_404() - parser = reqparse.RequestParser() - parser.add_argument('repository', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. repository=fake)') - parser.add_argument('tag', required=True, trim=True, nullable=False, - type=non_empty_string, help='{error_msg} (e.g. tag=0.0.4)') - args = parser.parse_args(strict=True) - username = authenticate(AuthenticationType.USER, request) - destinations = {} - destinations[host.server] = {host} - return install(username, args['repository'], args['tag'], - destinations, InstallationType.HOST) - return {} - -def retrieveAnnotatedTags(gitrepo): - atags = set() - for atag in gitrepo.tags: - if atag.tag != None: - atags.add(atag) - return atags - -def updateRepo(repo): - gitrepo = None - atagsBefore = set() - repoPath = app.config['GIT_TREES_DIR'] + repo.name - if os.path.isdir(repoPath): - gitrepo = git.Repo(repoPath) - gitrepo.git.clean("-fdx") - gitrepo.git.reset('--hard') - gitrepo.git.checkout("master") - atagsBefore = retrieveAnnotatedTags(gitrepo) - gitrepo.remotes.origin.fetch() - gitrepo.submodule_update(recursive=True, init=False, force_reset=True) - else: - gitrepo = git.Repo.clone_from(repo.provider.url + repo.name, to_path=repoPath) - gitrepo.submodule_update(recursive=True, init=True, force_reset=False) - atagsAfter = set() - atagsAfter = retrieveAnnotatedTags(gitrepo) - return gitrepo, atagsAfter - atagsBefore - - -if __name__ == '__main__': - # Configure Flask - app.config['SQLALCHEMY_DATABASE_URI'] = args.db - app.config['MAIL_SERVER'] = args.smtpserver - app.config['MAIL_DOMAIN'] = args.smtpdomain - app.config['MAIL_DEFAULT_SENDER'] = args.smtpsender + "@" + args.smtpdomain - app.config['FILES_STORE_DIR'] = args.store - app.config['GIT_TREES_DIR'] = args.repo - app.config['LDAP_URL'] = args.ldap - app.config['BUNDLE_ERRORS'] = True - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False - if args.port != "443": - app.debug = True - app.config['SQLALCHEMY_ECHO'] = True - - # Configure SQLAclhemy - db.app = app - db.init_app(app) - - # Create all DB tables if necessary - db.create_all() - - # Creates REST endpoints - v2.add_resource(CSHandler, '/cs', '/cs/') - v2.add_resource(UsersHandler, '/cs/users', '/cs/users/') - v2.add_resource(UserHandler, '/cs/users/<string:username>', - '/cs/users/<string:username>/') - v2.add_resource(ArchitecturesHandler, '/cs/architectures', '/cs/architectures/') - v2.add_resource(ArchitectureHandler, '/cs/architectures/<string:archname>', - '/cs/architectures/<string:archname>/') - v2.add_resource(DistributionsHandler, '/cs/distributions', '/cs/distributions/') - v2.add_resource(DistributionHandler, '/cs/distributions/<string:distroid>', - '/cs/distributions/<string:distroid>/') - v2.add_resource(PlatformsHandler, '/cs/platforms', '/cs/platforms/') - v2.add_resource(PlatformHandler, '/cs/platforms/<int:platid>', - '/cs/platforms/<int:platid>/') - v2.add_resource(BuildersHandler,'/cs/builders', '/cs/builders/') - v2.add_resource(BuilderHandler, '/cs/builders/<string:buildername>', - '/cs/builders/<string:buildername>/') - v2.add_resource(ServersHandler, '/cs/servers', '/cs/servers/') - v2.add_resource(ServerHandler, '/cs/servers/<string:servername>', - '/cs/servers/<string:servername>/') - v2.add_resource(ProvidersHandler, '/cs/providers', '/cs/providers/') - v2.add_resource(ProviderHandler, '/cs/servers/<int:providerid>', - '/cs/providers/<int:providerid>/') - v2.add_resource(RepositoriesHandler, '/cs/repositories', '/cs/repositories/') - v2.add_resource(RepositoryHandler, '/cs/repositories/<int:repositoryid>', - '/cs/repositories/<int:repositoryid>/') - v2.add_resource(FacilitiesHandler, '/cs/facilities', '/cs/facilities/') - v2.add_resource(FacilityHandler, '/cs/facilities/<string:facilityname>', - '/cs/facilities/<string:facilityname>/') - v2.add_resource(HostsHandler, '/cs/facilities/<string:facilityname>/hosts', - '/cs/facilities/<string:facilityname>/hosts/') - v2.add_resource(HostHandler, - '/cs/facilities/<string:facilityname>/hosts/<string:hostname>', - '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/') -# v2.add_resource(FilesHandler, -# '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/files', -# '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/files/') -# v2.add_resource(FileHandler, -# '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/files/<string:filename>', -# '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/files/<string:filename>/') - - v2.add_resource(CSInstallationsHandler, '/cs/installations', - '/cs/installations/', '/cs/facilities/installations', - '/cs/facilities/installations/') - v2.add_resource(FacilityInstallationsHandler, - '/cs/facilities/<string:facilityname>/installations', - '/cs/facilities/<string:facilityname>/installations/', - '/cs/facilities/<string:facilityname>/hosts/installations', - '/cs/facilities/<string:facilityname>/hosts/installations/') - v2.add_resource(HostInstallationsHandler, - '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/installations', - '/cs/facilities/<string:facilityname>/hosts/<string:hostname>/installations/') - - if args.port != "443": - app.run(host='0.0.0.0', port=args.port, threaded=True, - use_reloader=False, use_debugger=False) - else: - app.run(host='0.0.0.0', port=args.port, threaded=True, - ssl_context=('/etc/ssl/certs/inau_elettra_eu.pem', - '/etc/ssl/private/inau_elettra_eu.key'), - use_reloader=False, use_debugger=False)