Ejemplo n.º 1
0
def init_db(fname: str, path: str = None):
    if path:
        db_path = pathlib.Path(path) / fname
    else:
        db_path = pathlib.Path(fname)

    if db_path.exists():
        db_path.unlink()

    db_url = f"sqlite:///{db_path}"

    session_factory = new_session_factory(url=db_url)
    db = session_factory()

    users = [
        User(name="Alice", admin=True),
        User(name="Bob", admin=False),
        User(name="Charlie", admin=False),
    ]
    groups = [
        Group(name="group1", users=[users[0], users[1]]),
        Group(name="group2", users=[users[0], users[2]]),
        Group(name="group3", users=[users[1], users[2]]),
    ]
    projects = [
        Project(name="project1", groups=[groups[0], groups[1]]),
        Project(name="project2", groups=[groups[1], groups[2]]),
    ]
    items = users + groups + projects

    for item in items:
        db.add(item)

    db.commit()
    return db
Ejemplo n.º 2
0
    def __init__(self, cdsconfig, db):
        self.spawn_allow_group = cdsconfig.spawn_allow_group
        self.spawn_block_group = cdsconfig.spawn_block_group

        self.spawn_allow_group_orm = None
        self.spawn_block_group_orm = None

        created_group = False

        if self.spawn_allow_group != '':
            group = Group.find(db, self.spawn_allow_group)
            if group is None:
                group = Group(name=self.spawn_allow_group)
                db.add(group)
                created_group = True
            self.spawn_allow_group_orm = group

        if self.spawn_block_group != '':
            group = Group.find(db, self.spawn_block_group)
            if group is None:
                group = Group(name=self.spawn_block_group)
                db.add(group)
                created_group = True
            self.spawn_block_group_orm = group

        if created_group:
            self.db.commit()
Ejemplo n.º 3
0
    async def post(self, groupname):

        current_user = await self.get_current_user()

        if not current_user.admin:
            return self.send_error(403)

        group = Group.find(self.db, groupname)

        if group is None:
            return self.send_error(404)

        errors = DefaultObjDict()

        existing_group_users = group.users

        selected_users = self.get_arguments('selected_users[]')

        selected_users_orm = self.db.query(User).filter(
            User.name.in_(selected_users)).all()

        if self.sync_group(group, selected_users_orm):
            self.db.add(group)
            self.db.commit()

        self.redirect('{}hub/groupslist'.format(self.settings['base_url']))
Ejemplo n.º 4
0
    async def get(self, groupname):

        current_user = await self.get_current_user()

        if not current_user.admin:
            return self.send_error(403)

        group = Group.find(self.db, groupname)

        if group is None:
            return self.send_error(404)

        errors = DefaultObjDict()

        existing_group_users = group.users

        all_users_tuples = self.get_visitor_tuples(None, existing_group_users)

        html = await self.render_template(
            "editgroup.html",
            base_url=self.settings['base_url'],
            group=group,
            errors=errors,
            all_users_tuples=all_users_tuples
        )
        self.write(html)
Ejemplo n.º 5
0
    async def post(self, dashboard_urlname=None):

        current_user = await self.get_current_user()

        if not self.can_user_spawn(current_user):
            return self.send_error(403)

        dashboard = None
        group = None

        if dashboard_urlname is not None:
            # Edit (not new)

            dashboard = Dashboard.find(db=self.db,
                                       urlname=dashboard_urlname,
                                       user=current_user)

            if dashboard is None:
                return self.send_error(404)

            if current_user.name != dashboard.user.name:
                return self.send_error(403)

            group = dashboard.group

        dashboard_name = self.get_argument('name').strip()

        dashboard_description = self.get_argument('description').strip()

        dashboard_presentation_type = self.get_argument(
            'presentation_type').strip()

        dashboard_start_path = self.get_argument('start_path').strip()

        errors = DefaultObjDict()

        # Presentation basics

        if dashboard_name == '':
            errors.name = 'Please enter a name'
        elif not self.name_regex.match(dashboard_name):
            errors.name = 'Please use letters and digits (start with one of these), and then spaces or these characters _-!@$()*+?<>\'". Max 100 chars.'

        if '..' in dashboard_start_path:
            errors.start_path = 'Path must not contain ..'
        elif len(dashboard_start_path) and dashboard_start_path[0] == '/':
            errors.start_path = 'Path must be relative to Jupyter tree home or Git repo root (not starting with /)'
        elif not self.start_path_regex.match(dashboard_start_path):
            errors.start_path = 'Please enter valid URL path characters'

        cdsconfig = CDSConfigStore.get_instance(self.settings['config'])

        merged_presentation_types = cdsconfig.merged_presentation_types
        all_conda_envs = cdsconfig.conda_envs
        allow_custom_conda_env = cdsconfig.allow_custom_conda_env

        if not dashboard_presentation_type in merged_presentation_types:
            errors.presentation_type = 'Framework {} invalid - it must be one of the allowed types: {}'.format(
                dashboard_presentation_type,
                ', '.join(merged_presentation_types))

        # Visitors allowed
        selected_users = self.get_arguments('selected_users[]')

        selected_users_orm = self.db.query(User).filter(
            User.name.in_(selected_users)).all()

        user_permissions = self.get_argument(
            'user_permissions', cdsconfig.default_allow_all and 'anyusers'
            or 'selectedusers').strip()

        if user_permissions not in ('anyusers', 'selectedusers'):
            user_permissions = cdsconfig.default_allow_all and 'anyusers' or 'selectedusers'
            errors.user_permissions = 'You must choose either anyusers or selectedusers'

        # Dashboard options
        dashboard_options = {}

        git_repo = ''
        git_repo_branch = ''
        source_type = self.get_argument('source_type', '').strip()

        if cdsconfig.show_source_git and source_type == 'gitrepo':
            git_repo = self.get_argument('git_repo', '').strip()
            git_repo_branch = self.get_argument('git_repo_branch', '').strip()

            if git_repo != '':
                if not re.match(
                        '^((git|ssh|http(s)?)|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(/)?$',
                        git_repo):
                    errors.git_repo = 'Please enter a valid git repo URL'
        else:
            source_type = 'jupytertree'

        conda_env = self.get_argument('conda_env', '').strip()

        if conda_env != '':
            if allow_custom_conda_env:
                if not self.conda_env_regex.match(conda_env):
                    errors.conda_env = 'Please use letters and digits, spaces or these characters _-!@$()*+?<>/\\\'".'
                    conda_env = ''
            elif conda_env not in all_conda_envs:
                errors.conda_env = 'Please select a valid Conda env (\'{}\' is not in the allowed list)'.format(
                    conda_env)
                conda_env = ''

        dashboard_options['source_type'] = source_type
        dashboard_options['git_repo'] = git_repo
        dashboard_options['git_repo_branch'] = git_repo_branch
        dashboard_options['conda_env'] = conda_env

        spawners = []
        spawner = None
        spawner_id = ''

        if cdsconfig.show_source_servers:
            spawners = self.get_source_spawners(current_user)
            spawner, spawner_id = self.read_spawner(
                dashboard, spawners, dashboard_options, errors,
                cdsconfig.require_source_server)

        if len(errors) == 0:
            db = self.db

            try:

                orm_spawner = None
                if spawner:
                    orm_spawner = spawner.orm_spawner

                if dashboard is None:

                    urlname = self.calc_urlname(dashboard_name)

                    self.log.debug('Final urlname is ' + urlname)

                    dashboard = Dashboard(
                        name=dashboard_name,
                        urlname=urlname,
                        user=current_user.orm_user,
                        description=dashboard_description,
                        start_path=dashboard_start_path,
                        presentation_type=dashboard_presentation_type,
                        source_spawner=orm_spawner,
                        options=dashboard_options,
                        allow_all=user_permissions == 'anyusers')
                    self.log.debug('dashboard urlname ' + dashboard.urlname +
                                   ', main name ' + dashboard.name)

                else:
                    dashboard.name = dashboard_name
                    dashboard.description = dashboard_description
                    dashboard.start_path = dashboard_start_path
                    dashboard.presentation_type = dashboard_presentation_type
                    dashboard.source_spawner = orm_spawner
                    dashboard.options = dashboard_options
                    allow_all = user_permissions == 'anyusers'
                    dashboard.allow_all = allow_all

                if group is None:
                    group = Group.find(db, dashboard.groupname)
                    if group is None:
                        group = Group(name=dashboard.groupname)
                        self.db.add(group)
                    dashboard.group = group

                db.add(dashboard)

                if self.sync_group(group, selected_users_orm):
                    db.add(group)

                db.commit()

                # Now cancel any existing build and force a rebuild

                builders_store = BuildersStore.get_instance(
                    self.settings['config'])
                builder = builders_store[dashboard]

                dashboard_user = self._user_from_orm(dashboard.user.name)

                next_page = await self.maybe_start_build(
                    dashboard, dashboard_user, True)
                # next_page can be progress/options/dashboard, but actually can't be anything because with force_start==True
                # it will have set things off async!

            except Exception as e:
                errors.all = str(e)

        if len(errors):

            git_repo = dashboard_options['git_repo'] = dashboard_options.get(
                'git_repo', '')
            git_repo_branch = dashboard_options[
                'git_repo_branch'] = dashboard_options.get(
                    'git_repo_branch', '')
            conda_env = dashboard_options['conda_env'] = dashboard_options.get(
                'conda_env', '')
            all_users_tuples = self.get_visitor_tuples(current_user.id,
                                                       selected_users_orm)

            html = await self.render_template(
                "editdashboard.html",
                **self.template_vars(
                    dict(
                        dashboard=dashboard,
                        dashboard_name=dashboard_name,
                        dashboard_description=dashboard_description,
                        dashboard_start_path=dashboard_start_path,
                        dashboard_presentation_type=dashboard_presentation_type,
                        dashboard_options=dashboard_options,
                        user_permissions=user_permissions,
                        git_repo=git_repo,
                        git_repo_branch=git_repo_branch,
                        source_type=source_type,
                        conda_env=conda_env,
                        presentation_types=merged_presentation_types,
                        all_conda_envs=all_conda_envs,
                        allow_custom_conda_env=allow_custom_conda_env,
                        spawner_id=spawner_id,
                        spawners=spawners,
                        show_source_servers=cdsconfig.show_source_servers,
                        show_source_git=cdsconfig.show_source_git,
                        require_source_server=cdsconfig.require_source_server,
                        all_users_tuples=all_users_tuples,
                        errors=errors,
                        current_user=current_user)))
            return self.write(html)

        self.redirect(
            url_path_join(self.settings['base_url'], "hub", "dashboards",
                          dashboard.urlname))
Ejemplo n.º 6
0
    async def post(self, dashboard_urlname=None):

        current_user = await self.get_current_user()

        dashboard = None
        group = None

        if dashboard_urlname is not None:
            # Edit (not new)

            dashboard = Dashboard.find(db=self.db, urlname=dashboard_urlname, user=current_user)

            if dashboard is None:
                return self.send_error(404)

            if current_user.name != dashboard.user.name:
                return self.send_error(403)

            group = dashboard.group

        dashboard_name = self.get_argument('name').strip()

        dashboard_description = self.get_argument('description').strip()

        dashboard_presentation_type = self.get_argument('presentation_type').strip()

        dashboard_start_path = self.get_argument('start_path').strip()

        errors = DefaultObjDict()

        if dashboard_name == '':
            errors.name = 'Please enter a name'
        elif not self.name_regex.match(dashboard_name):
            errors.name = 'Please use letters and digits (start with one of these), and then spaces or these characters _-!@$()*+?<>. Max 100 chars.'

        if '..' in dashboard_start_path:
            errors.start_path = 'Path must not contain ..'
        elif not self.start_path_regex.match(dashboard_start_path):
            errors.start_path = 'Please enter valid URL path characters'

        merged_presentation_types = CDSConfigStore.get_instance(self.settings['config']).merged_presentation_types
        
        if not dashboard_presentation_type in merged_presentation_types:
            errors.presentation_type = 'Framework {} invalid - it must be one of the allowed types: {}'.format(
                dashboard_presentation_type, ', '.join(merged_presentation_types)
                )

        dashboard_options = self.read_options(dashboard, errors)

        spawners = self.get_source_spawners(current_user)

        spawner, spawner_name = self.read_spawner(dashboard, spawners, dashboard_options, errors)
  
        if len(errors) == 0:
            db = self.db

            try:

                orm_spawner = None
                if spawner:
                    orm_spawner = spawner.orm_spawner

                if dashboard is None:

                    urlname = self.calc_urlname(dashboard_name)    

                    self.log.debug('Final urlname is '+urlname)  

                    dashboard = Dashboard(
                        name=dashboard_name, urlname=urlname, user=current_user.orm_user, 
                        description=dashboard_description, start_path=dashboard_start_path, 
                        presentation_type=dashboard_presentation_type,
                        source_spawner=orm_spawner,
                        options=dashboard_options
                        )
                    self.log.debug('dashboard urlname '+dashboard.urlname+', main name '+dashboard.name)

                else:
                    dashboard.name = dashboard_name
                    dashboard.description = dashboard_description
                    dashboard.start_path = dashboard_start_path
                    dashboard.presentation_type = dashboard_presentation_type
                    dashboard.source_spawner = orm_spawner
                    dashboard.options = dashboard_options
                    
                if group is None:
                    group = Group.find(db, dashboard.groupname)
                    if group is None:
                        group = Group(name=dashboard.groupname)
                        self.db.add(group)
                    dashboard.group = group

                db.add(dashboard)
                    
                db.commit()

                # Now cancel any existing build and force a rebuild
                # TODO delete existing final_spawner
                builders_store = BuildersStore.get_instance(self.settings['config'])
                builder = builders_store[dashboard]

                async def do_restart_build(_):
                    await self.maybe_start_build(dashboard, current_user, True)
                    self.log.debug('Force build start')

                if builder.pending and builder._build_future and not builder._build_future.done():

                    self.log.debug('Cancelling build')
                    builder._build_future.add_done_callback(do_restart_build)
                    builder._build_future.cancel()

                else:
                    await do_restart_build(None)


            except Exception as e:
                errors.all = str(e)

        if len(errors):

            html = self.render_template(
                "editdashboard.html",
                **self.template_vars(dict(
                base_url=self.settings['base_url'],
                dashboard=dashboard,
                dashboard_name=dashboard_name,
                dashboard_description=dashboard_description,
                dashboard_start_path=dashboard_start_path,
                dashboard_presentation_type=dashboard_presentation_type,
                dashboard_options=dashboard_options,
                presentation_types=merged_presentation_types,
                spawner_name=spawner_name,
                spawners=spawners,
                errors=errors,
                current_user=current_user))
            )
            return self.write(html)
        
        self.redirect("{}hub/dashboards/{}".format(self.settings['base_url'], dashboard.urlname))