Esempio n. 1
0
    def get(self, app):
        app = App.query.filter(App.name == app).first()
        if app is None:
            return self.error('Invalid app',
                              name='invalid_resource',
                              status_code=404)

        deploy_config = TaskConfig.query.filter(
            TaskConfig.app_id == app.id,
            TaskConfig.type == TaskConfigType.deploy,
        ).first()
        if deploy_config is None:
            return self.error('Missing deploy config',
                              name='missing_conf',
                              status_code=404)

        context = serialize(app)
        context.update({
            'provider': deploy_config.provider,
            'provider_config': deploy_config.provider_config,
            'notifiers': deploy_config.notifiers,
            'checks': deploy_config.checks,
        })

        return self.respond(context)
Esempio n. 2
0
    def put(self, **kwargs):
        deploy = self._get_deploy(**kwargs)
        if deploy is None:
            return self.error("Invalid deploy",
                              name="invalid_resource",
                              status_code=404)

        with lock(redis, f"deploy:{deploy.id}", timeout=5):
            # we have to refetch in order to ensure lock state changes
            deploy = Deploy.query.get(deploy.id)
            task = Task.query.get(deploy.task_id)
            args = self.put_parser.parse_args()
            if args.status:
                assert task.status in (TaskStatus.pending,
                                       TaskStatus.in_progress)
                assert args.status == "cancelled"
                did_cancel = task.status == TaskStatus.pending
                task.status = TaskStatus.cancelled

            db.session.add(task)
            db.session.commit()

        if args.status and did_cancel:
            send_task_notifications(task, NotifierEvent.TASK_FINISHED)

        return self.respond(serialize(deploy))
Esempio n. 3
0
    def test_locked(self):
        user = self.create_user()
        repo = self.create_repo()
        app = self.create_app(repository=repo)

        result = serialize(app)
        assert result['id'] == str(app.id)
        assert result['name'] == app.name
Esempio n. 4
0
    def get(self, **kwargs):
        """
        Retrive a task.
        """
        task = self._get_task(**kwargs)
        if task is None:
            return self.error('Invalid task', name='invalid_resource', status_code=404)

        return self.respond(serialize(task))
Esempio n. 5
0
    def get(self, **kwargs):
        """
        Retrive a task.
        """
        deploy = self._get_deploy(**kwargs)
        if deploy is None:
            return self.error('Invalid deploy', name='invalid_resource', status_code=404)

        return self.respond(serialize(deploy))
Esempio n. 6
0
    def get(self, **kwargs):
        """
        Retrive a task.
        """
        task = self._get_task(**kwargs)
        if task is None:
            return self.error('Invalid task',
                              name='invalid_resource',
                              status_code=404)

        return self.respond(serialize(task))
Esempio n. 7
0
    def get(self, task_id):
        """
        Retrive a task.
        """
        task = Task.query.get(task_id)
        if task is None:
            return self.error('Invalid task',
                              name='invalid_resource',
                              status_code=404)

        return self.respond(serialize(task))
Esempio n. 8
0
    def put(self, **kwargs):
        task = self._get_task(**kwargs)
        if task is None:
            return self.error('Invalid task', name='invalid_resource', status_code=404)

        args = self.put_parser.parse_args()
        if args.status:
            assert task.status in (TaskStatus.pending, TaskStatus.in_progress)
            assert args.status == 'cancelled'
            task.status = TaskStatus.cancelled
        db.session.add(task)
        db.session.commit()

        return self.respond(serialize(task))
Esempio n. 9
0
    def get(self, app):
        app = App.query.filter(App.name == app).first()
        if app is None:
            return self.error('Invalid app', name='invalid_resource', status_code=404)

        context = serialize(app)
        context.update({
            'provider': app.provider,
            'provider_config': app.provider_config,
            'notifiers': app.notifiers,
            'checks': app.checks,
        })

        return self.respond(context)
Esempio n. 10
0
    def get(self):
        """
        Retrieve a list of apps.
        """
        args = self.get_parser.parse_args()

        qs_filters = []

        if args.name:
            qs_filters.append(App.name == args.name)

        app_qs = App.query.filter(*qs_filters).order_by(App.name.asc())

        return self.respond(serialize(list(app_qs)))
Esempio n. 11
0
    def post(self):
        """
        Create a new app.
        """
        args = self.post_parser.parse_args()

        provider_config = parse_provider_config(args.provider, args.provider_config or {})

        checks_config = parse_checks_config(args.checks or [])

        notifiers_config = parse_notifiers_config(args.notifiers or [])

        environments_config = parse_environments_config(args.environments or {})

        # TODO(dcramer): this needs to be a get_or_create pattern
        repo = Repository.query.filter(
            Repository.url == args.repository,
        ).first()
        if repo is None:
            repo = Repository(url=args.repository, vcs='git')
            db.session.add(repo)
            db.session.flush()

        app = App(
            name=args.name,
            repository_id=repo.id,
            data={
                'environments': environments_config,
            },
        )
        db.session.add(app)
        db.session.flush()

        # For backwards compatibility, we assume that we need a deploy TaskConfig
        # on the app at all times.
        deploy_config = TaskConfig(
            app_id=app.id,
            type=TaskConfigType.deploy,
            provider=args.provider,
            data={
                'provider_config': provider_config,
                'notifiers': notifiers_config,
                'checks': checks_config,
            },
        )
        db.session.add(deploy_config)
        db.session.commit()

        return self.respond(serialize(app), status_code=201)
Esempio n. 12
0
    def test_locked(self):
        user = self.create_user()
        repo = self.create_repo()
        app = self.create_app(repository=repo)
        task = self.create_task(app=app, user=user, status=TaskStatus.pending)

        result = serialize(task)
        assert result["id"] == str(task.id)
        assert result["status"] == "pending"
        assert result["ref"] == task.ref
        assert result["sha"] == task.sha
        assert result["environment"] == task.environment
        assert result["number"] == task.number
        assert result["app"]["id"] == str(app.id)
        assert result["app"]["name"] == app.name
Esempio n. 13
0
    def test_locked(self):
        user = self.create_user()
        repo = self.create_repo()
        app = self.create_app(repository=repo)
        task = self.create_task(app=app, user=user, status=TaskStatus.pending)

        result = serialize(task)
        assert result['id'] == str(task.id)
        assert result['status'] == 'pending'
        assert result['ref'] == task.ref
        assert result['sha'] == task.sha
        assert result['environment'] == task.environment
        assert result['number'] == task.number
        assert result['app']['id'] == str(app.id)
        assert result['app']['name'] == app.name
Esempio n. 14
0
    def put(self, task_id):
        task = Task.query.get(task_id)
        if task is None:
            return self.error('Invalid task',
                              name='invalid_resource',
                              status_code=404)

        args = self.put_parser.parse_args()
        if args.status:
            assert task.status in (TaskStatus.pending, TaskStatus.in_progress)
            assert args.status == 'cancelled'
            task.status = TaskStatus.cancelled
        db.session.add(task)
        db.session.commit()

        return self.respond(serialize(task))
Esempio n. 15
0
    def post(self):
        """
        Create a new app.
        """
        args = self.post_parser.parse_args()

        provider_config = parse_provider_config(
            args.provider, args.provider_config or {}
        )

        checks_config = parse_checks_config(args.checks or [])

        notifiers_config = parse_notifiers_config(args.notifiers or [])

        environments_config = parse_environments_config(args.environments or {})

        # TODO(dcramer): this needs to be a get_or_create pattern
        repo = Repository.query.filter(Repository.url == args.repository).first()
        if repo is None:
            repo = Repository(url=args.repository, vcs="git")
            db.session.add(repo)
            db.session.flush()

        app = App(
            name=args.name,
            repository_id=repo.id,
            data={"environments": environments_config},
        )
        db.session.add(app)
        db.session.flush()

        # For backwards compatibility, we assume that we need a deploy TaskConfig
        # on the app at all times.
        deploy_config = TaskConfig(
            app_id=app.id,
            type=TaskConfigType.deploy,
            provider=args.provider,
            data={
                "provider_config": provider_config,
                "notifiers": notifiers_config,
                "checks": checks_config,
            },
        )
        db.session.add(deploy_config)
        db.session.commit()

        return self.respond(serialize(app), status_code=201)
Esempio n. 16
0
    def test_locked(self):
        user = self.create_user()
        repo = self.create_repo()
        app = self.create_app(repository=repo)
        self.create_taskconfig(app=app)
        task = self.create_task(app=app, user=user, status=TaskStatus.pending)
        deploy = self.create_deploy(app=app, task=task)

        result = serialize(deploy)
        assert result['id'] == str(deploy.id)
        assert result['status'] == 'pending'
        assert result['ref'] == task.ref
        assert result['sha'] == task.sha
        assert result['environment'] == deploy.environment
        assert result['number'] == deploy.number
        assert result['app']['id'] == str(app.id)
        assert result['app']['name'] == app.name
Esempio n. 17
0
    def get(self, app):
        app = App.query.filter(App.name == app).first()
        if app is None:
            return self.error('Invalid app',
                              name='invalid_resource',
                              status_code=404)

        context = serialize(app)
        context.update({
            'provider': app.provider,
            'provider_config': app.provider_config,
            'notifiers': app.notifiers,
            'checks': app.checks,
            'environments': app.environments,
        })

        return self.respond(context)
Esempio n. 18
0
    def get(self):
        """
        Retrieve daily statistics for tasks.
        """
        end_date = date.today() - timedelta(days=30)

        results = dict(
            db.session.query(func.date(Task.date_started), func.count())
            .filter(Task.date_started > end_date)
            .group_by(func.date(Task.date_started))
        )

        points = []
        for day in range(31):
            point_date = end_date + timedelta(days=day)
            points.append((int(point_date.strftime("%s")), results.get(point_date, 0)))

        return self.respond(serialize(points), status_code=200)
Esempio n. 19
0
    def get(self, app):
        app = App.query.filter(App.name == app).first()
        if app is None:
            return self.error('Invalid app', name='invalid_resource', status_code=404)

        deploy_config = TaskConfig.query.filter(
            TaskConfig.app_id == app.id,
            TaskConfig.type == TaskConfigType.deploy,
        ).first()
        if deploy_config is None:
            return self.error('Missing deploy config', name='missing_conf', status_code=404)

        context = serialize(app)
        context.update({
            'provider': deploy_config.provider,
            'provider_config': deploy_config.provider_config,
            'notifiers': deploy_config.notifiers,
            'checks': deploy_config.checks,
        })

        return self.respond(context)
Esempio n. 20
0
    def put(self, **kwargs):
        task = self._get_task(**kwargs)
        if task is None:
            return self.error('Invalid task', name='invalid_resource', status_code=404)

        with lock(redis, 'task:{}'.format(task.id), timeout=5):
            # we have to refetch in order to ensure lock state changes
            task = Task.query.get(task.id)
            args = self.put_parser.parse_args()
            if args.status:
                assert task.status in (TaskStatus.pending, TaskStatus.in_progress)
                assert args.status == 'cancelled'
                did_cancel = task.status == TaskStatus.pending
                task.status = TaskStatus.cancelled

            db.session.add(task)
            db.session.commit()

        if args.status and did_cancel:
            send_task_notifications(task, NotifierEvent.TASK_FINISHED)

        return self.respond(serialize(task))
Esempio n. 21
0
    def post(self):
        """
        Create a new app.
        """
        args = self.post_parser.parse_args()

        provider_config = parse_provider_config(args.provider,
                                                args.provider_config or {})

        checks_config = parse_checks_config(args.checks or [])

        notifiers_config = parse_notifiers_config(args.notifiers or [])

        environments_config = parse_environments_config(args.environments
                                                        or {})

        # TODO(dcramer): this needs to be a get_or_create pattern
        repo = Repository.query.filter(
            Repository.url == args.repository, ).first()
        if repo is None:
            repo = Repository(url=args.repository, vcs='git')
            db.session.add(repo)
            db.session.flush()

        app = App(
            name=args.name,
            repository_id=repo.id,
            provider=args.provider,
            data={
                'provider_config': provider_config,
                'notifiers': notifiers_config,
                'checks': checks_config,
                'environments': environments_config,
            },
        )
        db.session.add(app)
        db.session.commit()

        return self.respond(serialize(app), status_code=201)
Esempio n. 22
0
    def post(self):
        """
        Create a new app.
        """
        args = self.post_parser.parse_args()

        provider_config = parse_provider_config(args.provider, args.provider_config or {})

        checks_config = parse_checks_config(args.checks or [])

        notifiers_config = parse_notifiers_config(args.notifiers or [])

        environments_config = parse_environments_config(args.environments or {})

        # TODO(dcramer): this needs to be a get_or_create pattern
        repo = Repository.query.filter(
            Repository.url == args.repository,
        ).first()
        if repo is None:
            repo = Repository(url=args.repository, vcs='git')
            db.session.add(repo)
            db.session.flush()

        app = App(
            name=args.name,
            repository_id=repo.id,
            provider=args.provider,
            data={
                'provider_config': provider_config,
                'notifiers': notifiers_config,
                'checks': checks_config,
                'environments': environments_config,
            },
        )
        db.session.add(app)
        db.session.commit()

        return self.respond(serialize(app), status_code=201)
Esempio n. 23
0
    def get(self, app):
        app = App.query.filter(App.name == app).first()
        if app is None:
            return self.error("Invalid app",
                              name="invalid_resource",
                              status_code=404)

        deploy_config = TaskConfig.query.filter(
            TaskConfig.app_id == app.id,
            TaskConfig.type == TaskConfigType.deploy).first()
        if deploy_config is None:
            return self.error("Missing deploy config",
                              name="missing_conf",
                              status_code=404)

        context = serialize(app)
        context.update({
            "provider": deploy_config.provider,
            "provider_config": deploy_config.provider_config,
            "notifiers": deploy_config.notifiers,
            "checks": deploy_config.checks,
        })

        return self.respond(context)
Esempio n. 24
0
    def get(self):
        """
        Retrieve daily statistics for tasks.
        """
        end_date = date.today() - timedelta(days=30)

        results = dict(db.session.query(
            func.date(Task.date_started),
            func.count(),
        ).filter(
            Task.date_started > end_date,
        ).group_by(
            func.date(Task.date_started),
        ))

        points = []
        for day in range(31):
            point_date = end_date + timedelta(days=day)
            points.append((
                int(point_date.strftime('%s')),
                results.get(point_date, 0),
            ))

        return self.respond(serialize(points), status_code=200)
Esempio n. 25
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()

        user = get_current_user()
        if not user:
            username = args.user
            if not username:
                return self.error('Missing required argument "user"',
                                  status_code=400)

            with lock(redis, f"user:create:{username}", 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 == username).first()
                if not user:
                    user = User(name=username)
                    db.session.add(user)
                    db.session.flush()
        elif args.user:
            return self.error(
                "Cannot specify user when using session authentication.",
                status_code=400,
            )

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

        deploy_config = TaskConfig.query.filter(
            TaskConfig.app_id == app.id,
            TaskConfig.type == TaskConfigType.deploy).first()
        if not deploy_config:
            return self.error("Missing deploy config",
                              name="missing_conf",
                              status_code=404)

        params = None

        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, f"repo:update:{repo.id}"):
            vcs_backend.clone_or_update()

        ref = args.ref or app.get_default_ref(args.env)

        # look for our special refs (prefixed via a colon)
        # TODO(dcramer): this should be supported outside of just this endpoint
        if ref.startswith(":"):
            sha = self._get_internal_ref(app, args.env, ref)
            if not sha:
                return self.error("Invalid ref",
                                  name="invalid_ref",
                                  status_code=400)
        else:
            try:
                sha = vcs_backend.get_sha(ref)
            except vcs.UnknownRevision:
                return self.error("Invalid ref",
                                  name="invalid_ref",
                                  status_code=400)

        if args.params is not None:
            params = args.params

        if not args.force:
            for check_config in deploy_config.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=str(e), name="check_failed")

        with lock(redis, f"deploy:create:{app.id}", timeout=5):
            task = Task(
                app_id=app.id,
                # TODO(dcramer): ref should default based on app config
                ref=ref,
                sha=sha,
                params=params,
                status=TaskStatus.pending,
                user_id=user.id,
                provider=deploy_config.provider,
                data={
                    "force": args.force,
                    "provider_config": deploy_config.provider_config,
                    "notifiers": deploy_config.notifiers,
                    "checks": deploy_config.checks,
                },
            )
            db.session.add(task)
            db.session.flush()
            db.session.refresh(task)

            deploy = Deploy(
                task_id=task.id,
                app_id=app.id,
                environment=args.env,
                number=DeploySequence.get_clause(app.id, args.env),
            )
            db.session.add(deploy)
            db.session.commit()

            send_task_notifications(task, NotifierEvent.TASK_QUEUED)

        return self.respond(serialize(deploy), status_code=201)
Esempio n. 26
0
    def put(self, app_id):
        """
        Update an app.
        """
        args = self.put_parser.parse_args()

        app = App.query.get(app_id)
        if app is None:
            return self.error('Invalid app', name='invalid_resource', status_code=404)

        if args.provider or args.provider_config:
            if args.provider is not None:
                provider = args.provider
            else:
                provider = app.provider

            if args.provider_config is not None:
                provider_config = args.provider_config
            else:
                provider_config = app.provider_config

            app.provider = provider
            app.data['provider_config'] = parse_provider_config(
                provider, provider_config
            )

        if args.notifiers is not None:
            app.data['notifiers'] = parse_notifiers_config(args.notifiers)

        if args.checks is not None:
            app.data['checks'] = parse_checks_config(args.checks)

        if args.environments is not None:
            app.data['environments'] = parse_environments_config(args.environments)

        if args.name:
            app.name = args.name

        # TODO(dcramer): this needs to be a get_or_create pattern
        if args.repository:
            repo = Repository.query.filter(
                Repository.url == args.repository,
            ).first()
            if repo is None:
                repo = Repository(url=args.repository, vcs='git')
                db.session.add(repo)
                db.session.flush()
            app.repository_id = repo.id

        db.session.add(app)
        db.session.commit()

        context = serialize(app)
        context.update({
            'provider': app.provider,
            'provider_config': app.provider_config,
            'notifiers': app.notifiers,
            'checks': app.checks,
        })

        return self.respond(context)
Esempio n. 27
0
    def put(self, app):
        """
        Update an app.
        """
        args = self.put_parser.parse_args()

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

        # For backwards compatibility, we assume that we need a deploy TaskConfig
        # on the app at all times.
        deploy_config = TaskConfig.query.filter(
            TaskConfig.app_id == app.id,
            TaskConfig.type == TaskConfigType.deploy,
        ).first()
        if deploy_config is None:
            deploy_config = TaskConfig(app_id=app.id, type=TaskConfigType.deploy)
            db.session.add(deploy_config)
            db.session.flush()

        if args.provider or args.provider_config:
            if args.provider is not None:
                provider = args.provider
            else:
                provider = deploy_config.provider

            if args.provider_config is not None:
                provider_config = args.provider_config
            else:
                provider_config = deploy_config.provider_config

            deploy_config.provider = provider
            deploy_config.data['provider_config'] = parse_provider_config(
                provider, provider_config
            )

        if args.notifiers is not None:
            deploy_config.data['notifiers'] = parse_notifiers_config(args.notifiers)

        if args.checks is not None:
            deploy_config.data['checks'] = parse_checks_config(args.checks)

        if args.environments is not None:
            app.data['environments'] = parse_environments_config(args.environments)

        if args.name:
            app.name = args.name

        # TODO(dcramer): this needs to be a get_or_create pattern
        if args.repository:
            repo = Repository.query.filter(
                Repository.url == args.repository,
            ).first()
            if repo is None:
                repo = Repository(url=args.repository, vcs='git')
                db.session.add(repo)
                db.session.flush()
            app.repository_id = repo.id

        db.session.add(app)
        db.session.add(deploy_config)
        db.session.commit()

        context = serialize(app)
        context.update({
            'provider': deploy_config.provider,
            'provider_config': deploy_config.provider_config,
            'notifiers': deploy_config.notifiers,
            'checks': deploy_config.checks,
        })

        return self.respond(context)
Esempio n. 28
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)
Esempio n. 29
0
    def test_simple(self):
        user = self.create_user()

        result = serialize(user)
        assert result['id'] == str(user.id)
        assert result['name'] == user.name
Esempio n. 30
0
    def put(self, app):
        """
        Update an app.
        """
        args = self.put_parser.parse_args()

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

        if args.provider or args.provider_config:
            if args.provider is not None:
                provider = args.provider
            else:
                provider = app.provider

            if args.provider_config is not None:
                provider_config = args.provider_config
            else:
                provider_config = app.provider_config

            app.provider = provider
            app.data['provider_config'] = parse_provider_config(
                provider, provider_config)

        if args.notifiers is not None:
            app.data['notifiers'] = parse_notifiers_config(args.notifiers)

        if args.checks is not None:
            app.data['checks'] = parse_checks_config(args.checks)

        if args.environments is not None:
            app.data['environments'] = parse_environments_config(
                args.environments)

        if args.name:
            app.name = args.name

        # TODO(dcramer): this needs to be a get_or_create pattern
        if args.repository:
            repo = Repository.query.filter(
                Repository.url == args.repository, ).first()
            if repo is None:
                repo = Repository(url=args.repository, vcs='git')
                db.session.add(repo)
                db.session.flush()
            app.repository_id = repo.id

        db.session.add(app)
        db.session.commit()

        context = serialize(app)
        context.update({
            'provider': app.provider,
            'provider_config': app.provider_config,
            'notifiers': app.notifiers,
            'checks': app.checks,
        })

        return self.respond(context)
Esempio n. 31
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()

        user = get_current_user()
        if not user:
            username = args.user
            if not username:
                return self.error('Missing required argument "user"',
                                  status_code=400)

            with lock(redis, 'user:create:{}'.format(username), 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 == username).first()
                if not user:
                    user = User(name=username)
                    db.session.add(user)
                    db.session.flush()
        elif args.user:
            return self.error(
                'Cannot specify user when using session authentication.',
                status_code=400)

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

        params = None

        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 = args.ref or app.get_default_ref(args.env)

        # look for our special refs (prefixed via a colon)
        # TODO(dcramer): this should be supported outside of just this endpoint
        if ref.startswith(':'):
            sha = self._get_internal_ref(app, args.env, ref)
            if not sha:
                return self.error('Invalid ref',
                                  name='invalid_ref',
                                  status_code=400)
        else:
            try:
                sha = vcs_backend.get_sha(ref)
            except vcs.UnknownRevision:
                return self.error('Invalid ref',
                                  name='invalid_ref',
                                  status_code=400)

        if args.params is not None:
            params = args.params

        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):
            task = Task(
                app_id=app.id,
                environment=args.env,
                number=TaskSequence.get_clause(app.id, args.env),
                # TODO(dcramer): ref should default based on app config
                ref=ref,
                sha=sha,
                params=params,
                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()

            send_task_notifications(task, NotifierEvent.TASK_QUEUED)

        return self.respond(serialize(task), status_code=201)
Esempio n. 32
0
    def test_simple(self):
        user = self.create_user()

        result = serialize(user)
        assert result["id"] == str(user.id)
        assert result["name"] == user.name
Esempio n. 33
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 = args.ref or app.get_default_ref(args.env)

        # look for our special refs (prefixed via a colon)
        # TODO(dcramer): this should be supported outside of just this endpoint
        if ref.startswith(':'):
            sha = self._get_internal_ref(app, args.env, ref)
            if not sha:
                return self.error('Invalid ref', name='invalid_ref', status_code=400)
        else:
            try:
                sha = vcs_backend.get_sha(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()

            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()

            send_task_notifications(task, NotifierEvent.TASK_QUEUED)

        return self.respond(serialize(task), status_code=201)
Esempio n. 34
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)