Example #1
0
def check_queue():
    """
    Checks the pending task queue and, given there's not an in-progress task
    for the given APP + ENV, marks the latest as in progress and fires the
    execute_task job.
    """
    pending_queues = list(db.session.query(
        Task.app_id, Task.environment
    ).filter(
        Task.status == TaskStatus.pending
    ).group_by(
        Task.app_id, Task.environment
    ))
    logging.info('Found pending tasks for %d queues', len(pending_queues))

    for app_id, environment in pending_queues:
        app = App.query.get(app_id)
        with lock(redis, 'taskcheck:{}-{}'.format(app.id, environment), timeout=5):
            if has_active_task(app.id, environment):
                logging.info('Task already in progress for %s/%s', app.name, environment)
                continue

            task_id = get_pending_task_id(app.id, environment)
            if not task_id:
                logging.info('Unable to find a pending task for %s/%s', app.name, environment)
                continue

            Task.query.filter(
                Task.id == task_id
            ).update({
                'status': TaskStatus.in_progress,
            }, synchronize_session=False)

            celery.send_task("freight.execute_task", [task_id])
Example #2
0
def check_queue():
    """
    Checks the pending task queue and, given there's not an in-progress task
    for the given APP + ENV, marks the latest as in progress and fires the
    execute_task job.
    """
    pending_queues = list(
        db.session.query(Task.app_id, Task.environment).filter(
            Task.status == TaskStatus.pending).group_by(
                Task.app_id, Task.environment))
    logging.info('Found pending tasks for %d queues', len(pending_queues))

    for app_id, environment in pending_queues:
        app = App.query.get(app_id)
        with lock(redis,
                  'taskcheck:{}-{}'.format(app.id, environment),
                  timeout=5):
            if has_active_task(app.id, environment):
                logging.info('Task already in progress for %s/%s', app.name,
                             environment)
                continue

            task_id = get_pending_task_id(app.id, environment)
            if not task_id:
                logging.info('Unable to find a pending task for %s/%s',
                             app.name, environment)
                continue

            Task.query.filter(Task.id == task_id).update(
                {
                    'status': TaskStatus.in_progress,
                },
                synchronize_session=False)

            celery.send_task("freight.execute_task", [task_id])
Example #3
0
    def delete(self, app_id):
        """
        Delete an app.
        """
        app = App.query.get(app_id)
        if app is None:
            return self.error('Invalid app', name='invalid_resource', status_code=404)

        celery.send_task("freight.delete_object", kwargs={'model': 'App', 'app_id': app.id})

        return self.respond({"id": str(app.id)})
Example #4
0
    def delete(self, app):
        """
        Delete an app.
        """
        app = App.query.filter(App.name == app).first()
        if app is None:
            return self.error('Invalid app',
                              name='invalid_resource',
                              status_code=404)

        celery.send_task("freight.delete_object",
                         kwargs={
                             'model': 'App',
                             'app_id': app.id
                         })

        return self.respond({"id": str(app.id)})
Example #5
0
    def post(self):
        """
        Given any constraints for a task are within acceptable bounds, create
        a new task and enqueue it.
        """
        args = self.post_parser.parse_args()

        app = App.query.filter(App.name == args.app).first()
        if not app:
            return self.error('Invalid app', name='invalid_resource', status_code=404)

        repo = Repository.query.get(app.repository_id)

        workspace = Workspace(
            path=repo.get_path(),
        )

        vcs_backend = vcs.get(
            repo.vcs,
            url=repo.url,
            workspace=workspace,
        )

        with lock(redis, 'repo:update:{}'.format(repo.id)):
            vcs_backend.clone_or_update()

        ref = app.get_default_ref(args.env)

        try:
            sha = vcs_backend.describe(ref)
        except vcs.UnknownRevision:
            return self.error('Invalid ref', name='invalid_ref', status_code=400)

        if not args.force:
            for check_config in app.checks:
                check = checks.get(check_config['type'])
                try:
                    check.check(app, sha, check_config['config'])
                except CheckPending:
                    pass
                except CheckError as e:
                    return self.error(
                        message=unicode(e),
                        name='check_failed',
                    )

        with lock(redis, 'task:create:{}'.format(app.id), timeout=5):
            # TODO(dcramer): this needs to be a get_or_create pattern and
            # ideally moved outside of the lock
            user = User.query.filter(User.name == args.user).first()
            if not user:
                user = User(name=args.user)
                db.session.add(user)
                db.session.flush()

            if not args.force and self._has_active_task(app, args.env):
                return self.error(
                    message='Another task is already in progress for this app/environment',
                    name='locked',
                )

            task = Task(
                app_id=app.id,
                environment=args.env,
                number=TaskSequence.get_clause(app.id, args.env),
                name=TaskName.deploy,
                # TODO(dcramer): ref should default based on app config
                ref=ref,
                sha=sha,
                status=TaskStatus.pending,
                user_id=user.id,
                provider=app.provider,
                data={
                    'force': args.force,
                    'provider_config': app.provider_config,
                    'notifiers': app.notifiers,
                    'checks': app.checks,
                },
            )
            db.session.add(task)
            db.session.commit()

        celery.send_task("freight.execute_task", [task.id])

        return self.respond(serialize(task), status_code=201)
Example #6
0
    def post(self):
        """
        Given any constraints for a task are within acceptable bounds, create
        a new task and enqueue it.
        """
        args = self.post_parser.parse_args()

        app = App.query.filter(App.name == args.app).first()
        if not app:
            return self.error('Invalid app',
                              name='invalid_resource',
                              status_code=404)

        repo = Repository.query.get(app.repository_id)

        workspace = Workspace(path=repo.get_path(), )

        vcs_backend = vcs.get(
            repo.vcs,
            url=repo.url,
            workspace=workspace,
        )

        with lock(redis, 'repo:update:{}'.format(repo.id)):
            vcs_backend.clone_or_update()

        ref = app.get_default_ref(args.env)

        try:
            sha = vcs_backend.describe(ref)
        except vcs.UnknownRevision:
            return self.error('Invalid ref',
                              name='invalid_ref',
                              status_code=400)

        if not args.force:
            for check_config in app.checks:
                check = checks.get(check_config['type'])
                try:
                    check.check(app, sha, check_config['config'])
                except CheckPending:
                    pass
                except CheckError as e:
                    return self.error(
                        message=unicode(e),
                        name='check_failed',
                    )

        with lock(redis, 'task:create:{}'.format(app.id), timeout=5):
            # TODO(dcramer): this needs to be a get_or_create pattern and
            # ideally moved outside of the lock
            user = User.query.filter(User.name == args.user).first()
            if not user:
                user = User(name=args.user)
                db.session.add(user)
                db.session.flush()

            if not args.force and self._has_active_task(app, args.env):
                return self.error(
                    message=
                    'Another task is already in progress for this app/environment',
                    name='locked',
                )

            task = Task(
                app_id=app.id,
                environment=args.env,
                number=TaskSequence.get_clause(app.id, args.env),
                name=TaskName.deploy,
                # TODO(dcramer): ref should default based on app config
                ref=ref,
                sha=sha,
                status=TaskStatus.pending,
                user_id=user.id,
                provider=app.provider,
                data={
                    'force': args.force,
                    'provider_config': app.provider_config,
                    'notifiers': app.notifiers,
                    'checks': app.checks,
                },
            )
            db.session.add(task)
            db.session.commit()

        celery.send_task("freight.execute_task", [task.id])

        return self.respond(serialize(task), status_code=201)