Beispiel #1
0
    def handle(self, provisioner_id):
        # TODO: block deletion of used provisioner on backend, not here
        clusters = self.kqueen_request('cluster', 'list')
        provisioner = self.kqueen_request('provisioner',
                                          'get',
                                          fnargs=(provisioner_id, ))
        used_provisioners = [
            p['id'] for p in [c['provisioner'] for c in clusters]
        ]

        if provisioner_id not in used_provisioners:
            self.kqueen_request('provisioner',
                                'delete',
                                fnargs=(provisioner_id, ))
            msg = 'Provisioner {} successfully deleted.'.format(
                provisioner['name'])
            user_logger.debug('{}:{}'.format(user_prefix(session), msg))
            flash(msg, 'success')
        else:
            msg = 'Provisioner {} is in use, cannot delete.'.format(
                provisioner['name'])
            user_logger.debug('{}:{}'.format(user_prefix(session), msg))
            flash(msg, 'warning')

        return redirect(
            request.environ.get('HTTP_REFERER', url_for('ui.index')))
Beispiel #2
0
    def handle(self):
        # Get all necessary objects from backend
        _provisioners = self.kqueen_request('provisioner', 'list')
        unknown_state = app.config['PROVISIONER_UNKNOWN_STATE']
        ok_state = app.config['PROVISIONER_OK_STATE']
        provisioners = [
            p for p in _provisioners
            if p.get('state', unknown_state) == ok_state
        ]
        engines = self.kqueen_request('provisioner', 'engines')
        engine_dict = dict([(e.pop('name'), e) for e in engines])

        # Append tagged parameter fields to form
        form_cls = ClusterCreateForm
        for provisioner in provisioners:
            engine = engine_dict.get(provisioner['engine'], {})
            _parameters = engine.get('parameters', {}).get('cluster', {})
            # Append provisioner ID to parameter name to make it unique
            parameters = {
                k + '__' + provisioner['id']: v
                for [k, v] in _parameters.items()
            }
            form_cls.append_fields(parameters, switchtag=provisioner['id'])

        # Instantiate form and populate provisioner choices
        form = form_cls()
        form.provisioner.choices = [(p['id'], p['name']) for p in provisioners]

        if form.validate_on_submit():
            try:
                # Filter out populated tagged fields and get their data
                metadata = {
                    k.split('__')[0]: v.data
                    for (k, v)
                    in form._fields.items()
                    if (hasattr(v, 'switchtag') and v.switchtag) and form.provisioner.data in k
                }
            except Exception as e:
                user_logger.exception('{}:{}'.format(user_prefix(session), e))
                flash('Invalid cluster metadata.', 'danger')
                render_template('ui/cluster_create.html', form=form)

            owner_ref = 'User:{}'.format(session['user']['id'])
            provisioner_id = form.provisioner.data
            cluster_kw = {
                'name': form.name.data,
                'state': app.config['CLUSTER_PROVISIONING_STATE'],
                'provisioner': 'Provisioner:{}'.format(provisioner_id),
                'created_at': datetime.utcnow(),
                'metadata': metadata,
                'owner': owner_ref
            }

            cluster = self.kqueen_request('cluster', 'create', fnargs=(cluster_kw,))
            msg = 'Provisioning of cluster {} is in progress.'.format(cluster['name'])
            user_logger.debug('{}:{}'.format(user_prefix(session), msg))
            flash(msg, 'success')
            return redirect(url_for('ui.index'))
        return render_template('ui/cluster_create.html', form=form)
Beispiel #3
0
    def handle(self):
        # Get engines with parameters
        engines = self.kqueen_request('provisioner', 'engines')
        # Append tagged parameter fields to form
        form_cls = ProvisionerCreateForm
        for engine in engines:
            _engine_parameters = engine['parameters']['provisioner']
            engine_parameters = {
                k + '__' + prettify_engine_name(engine['name']): v
                for (k, v) in _engine_parameters.items()
            }
            form_cls.append_fields(engine_parameters, switchtag=engine['name'])

        # Instantiate form and populate engine choices
        form = form_cls()
        form.engine.choices = [(e['name'], e['verbose_name']) for e in engines]

        if form.validate_on_submit():
            try:
                # Filter out populated tagged fields and get their data
                parameters = {
                    k.split('__')[0]: v.data
                    for (k, v) in form._fields.items()
                    if (hasattr(v, 'switchtag') and v.switchtag)
                    and prettify_engine_name(form.engine.data) in k
                }
            except Exception as e:
                msg = 'Failed to create Provisioner: Invalid parameters.'
                user_logger.exception('{}:{}'.format(user_prefix(session),
                                                     msg))
                flash(msg, 'danger')
                render_template('ui/provisioner_create.html', form=form)

            owner_ref = 'User:{}'.format(session['user']['id'])
            provisioner_kw = {
                'name': form.name.data,
                'engine': form.engine.data,
                'state': app.config['PROVISIONER_UNKNOWN_STATE'],
                'parameters': parameters,
                'created_at': datetime.utcnow(),
                'owner': owner_ref
            }
            provisioner = self.kqueen_request('provisioner',
                                              'create',
                                              fnargs=(provisioner_kw, ))
            msg = 'Provisioner {} successfully created.'.format(
                provisioner['name'])
            user_logger.debug('{}:{}'.format(user_prefix(session), msg))
            flash(msg, 'success')
            return redirect(url_for('ui.index'))
        return render_template('ui/provisioner_create.html', form=form)
Beispiel #4
0
    def handle(self, cluster_id):
        redirect_url = request.environ.get('HTTP_REFERER', url_for('ui.index'))

        cluster = self.kqueen_request('cluster', 'get', fnargs=(cluster_id,))
        policy = cluster['metadata'].get('network_policy', 'none')
        if 'node_count' not in cluster.get('metadata', {}):
            engine = cluster.get('provisioner', {}).get('engine', '<unknown>')
            flash('{} engine doesn\'t support network policy.'.format(
                prettify_engine_name(engine)), 'warning')
            return redirect(redirect_url)

        if policy.get('provider') == 'CALICO':
            if policy.get('enabled'):
                self.kqueen_request('cluster', 'set_network_policy', fnargs=(cluster_id, False))
                flash('Network policy was successfully disabled', 'success')
                return redirect(redirect_url)

            if int(cluster['metadata']['node_count']) < 2:
                flash('At least 2 nodes are required to enable network policy', 'error')
                return redirect(redirect_url)

            cluster = self.kqueen_request('cluster', 'set_network_policy',
                                          fnargs=(cluster_id, True))
            msg = 'Calico policy for cluster {} successfully enabled.'.format(cluster['name'])
            user_logger.debug('{}:{}'.format(user_prefix(session), msg))
            flash(msg, 'success')
        else:
            flash('Can not manage network policy for this cluster.', 'warning')
        return redirect(redirect_url)
Beispiel #5
0
 def handle(self, organization_id):
     organization = self.kqueen_request('organization',
                                        'get',
                                        fnargs=(organization_id, ))
     deletable = self.kqueen_request('organization',
                                     'deletable',
                                     fnargs=(organization_id, ))
     if not deletable.get('deletable', False):
         resources = ', '.join([
             '{} {}'.format(r['object'].lower(), r['name'])
             for r in deletable.get('remaining', [])
         ])
         flash(
             'Cannot delete organization {}, before deleting its resources: {}'
             .format(organization['name'], resources), 'warning')
         return redirect(
             request.environ.get('HTTP_REFERER',
                                 url_for('manager.overview')))
     self.kqueen_request('organization',
                         'delete',
                         fnargs=(organization_id, ))
     msg = 'Organization {} successfully deleted.'.format(
         organization['name'])
     user_logger.debug('{}:{}'.format(user_prefix(session), msg))
     flash(msg, 'success')
     return redirect(
         request.environ.get('HTTP_REFERER', url_for('manager.overview')))
Beispiel #6
0
 def handle(self, organization_id, user_id):
     user = self.kqueen_request('user', 'get', fnkwargs={'uuid': user_id})
     form = MemberChangeRoleForm()
     form.role.choices = tuple([rl for rl in ROLE_CHOICES if user['role'] not in rl])
     if form.validate_on_submit():
         user['role'] = form.role.data
         self.kqueen_request('user', 'update', fnkwargs={'uuid': user_id, 'payload': user})
         msg = 'Role of {} has been successfully updated.'.format(user['username'])
         user_logger.debug('{}:{}'.format(user_prefix(session), msg))
         flash(msg, 'success')
         return redirect(url_for('manager.organization_detail', organization_id=organization_id))
     return render_template('manager/member_change_role.html', form=form, username=user['username'], organization_id=organization_id)
Beispiel #7
0
 def handle(self, cluster_id):
     cluster = self.kqueen_request('cluster', 'get', fnargs=(cluster_id, ))
     if cluster['state'] == app.config['CLUSTER_PROVISIONING_STATE']:
         # TODO: handle state together with policies in helper for allowed table actions
         flash('Cannot delete clusters during provisioning.', 'warning')
         return redirect(
             request.environ.get('HTTP_REFERER', url_for('ui.index')))
     self.kqueen_request('cluster', 'delete', fnargs=(cluster_id, ))
     msg = 'Cluster {} successfully deleted.'.format(cluster['name'])
     user_logger.debug('{}:{}'.format(user_prefix(session), msg))
     flash(msg, 'success')
     return redirect(
         request.environ.get('HTTP_REFERER', url_for('ui.index')))
Beispiel #8
0
 def handle(self, cluster_id):
     cluster = self.kqueen_request('cluster', 'get', fnargs=(cluster_id,))
     if 'node_count' not in cluster.get('metadata', {}):
         engine = cluster.get('provisioner', {}).get('engine', '<unknown>')
         flash("{} engine doesn't support scaling.".format(prettify_engine_name(engine)), 'warning')
         return redirect(request.environ.get('HTTP_REFERER', url_for('ui.index')))
     current_node_count = cluster['metadata']['node_count']
     node_count = request.form['node_count']
     if current_node_count == node_count:
         return redirect(request.environ.get('HTTP_REFERER', url_for('ui.index')))
     self.kqueen_request('cluster', 'resize', fnargs=(cluster_id, node_count))
     msg = 'Cluster {} successfully resized.'.format(cluster['name'])
     user_logger.debug('{}:{}'.format(user_prefix(session), msg))
     flash(msg, 'success')
     return redirect(request.environ.get('HTTP_REFERER', url_for('ui.index')))
Beispiel #9
0
 def handle(self):
     form = OrganizationCreateForm()
     if form.validate_on_submit():
         organization_kw = {
             'name': form.organization_name.data,
             'namespace': slugify(form.organization_name.data),
             'created_at': datetime.utcnow()
         }
         try:
             organization = self.kqueen_request('organization', 'create', fnargs=(organization_kw,))
         except KQueenAPIException:
             return redirect(url_for('manager.overview'))
         msg = 'Organization {} successfully created.'.format(organization['name'])
         user_logger.debug('{}:{}'.format(user_prefix(session), msg))
         flash(msg, 'success')
         return redirect(url_for('manager.overview'))
     return render_template('manager/organization_create.html', form=form)
Beispiel #10
0
    def handle(self, organization_id):
        form = MemberCreateForm()
        if form.validate_on_submit():
            user_kw = {
                'username': form.email.data,
                'email': form.email.data,
                'password': generate_password(),
                'organization': 'Organization:{}'.format(organization_id),
                'created_at': datetime.utcnow(),
                'role': form.role.data,
                'active': True,
                'metadata': {}
            }
            user = self.kqueen_request('user',
                                       'create',
                                       fnkwargs={'payload': user_kw})

            # send mail
            token = generate_confirmation_token(user['email'])
            html = render_template('ui/email/user_invitation.html',
                                   username=user['username'],
                                   token=token,
                                   organization=user['organization']['name'])
            email = EmailMessage('[KQueen] Organization invitation',
                                 recipients=[user['email']],
                                 html=html)
            try:
                email.send()
            except Exception as e:
                msg = 'Could not send invitation e-mail, please try again later.'
                logger.exception(msg)
                self.kqueen_request('user',
                                    'delete',
                                    fnargs={'uuid', user['id']})
                flash(msg, 'danger')
                return render_template('manager/member_create.html', form=form)

            msg = 'Member {} successfully added.'.format(user['username'])
            user_logger.debug('{}:{}'.format(user_prefix(session), msg))
            flash(msg, 'success')
            return redirect(
                url_for('manager.organization_detail',
                        organization_id=organization_id))
        return render_template('manager/member_create.html',
                               form=form,
                               organization_id=organization_id)
Beispiel #11
0
    def handle(self, cluster_ids):
        for cluster_id in cluster_ids:
            cluster = self.kqueen_request('cluster', 'get', fnargs=(cluster_id,))
            msg = 'Cluster {} successfully deleted.'.format(cluster['name'])

            if cluster['provisioner']['engine'] == 'kqueen.engines.ManualEngine':
                flash('Manual Engine does not support cluster deleting, cluster will be detached.',
                      'warning')
                msg = 'Cluster {} successfully detached.'.format(cluster['name'])

            if cluster['state'] == app.config['CLUSTER_PROVISIONING_STATE']:
                # TODO: handle state together with policies in helper for allowed table actions
                flash('Cannot delete clusters during provisioning.', 'warning')
            else:
                self.kqueen_request('cluster', 'delete', fnargs=(cluster_id,))
                user_logger.debug('{}:{}'.format(user_prefix(session), msg))
                flash(msg, 'success')
        return redirect(url_for('ui.index'))
Beispiel #12
0
    def handle(self):
        # TODO: Add CN name validator (for LDAp username)

        form_cls = UserInviteForm

        auth_config = self.kqueen_request('configuration', 'auth')

        for auth_type, options in auth_config.items():
            ui_parameters = options['ui_parameters']
            # Add tag to field names to enable dynamic field switching
            ui_parameters = {k + '__' + auth_type: v for k, v in ui_parameters.items()}
            form_cls.append_fields(ui_parameters, switchtag=auth_type)

        form = form_cls()
        form.auth_method.choices = [(k, v['name']) for k, v in auth_config.items()]
        if form.validate_on_submit():

            organization = 'Organization:{}'.format(session['user']['organization']['id'])

            # Filter out populated tagged fields and get their data
            try:
                ui_filled_parameters = {
                    k.split('__')[0]: v.data
                    for (k, v)
                    in form._fields.items()
                    if (hasattr(v, 'switchtag') and v.switchtag) and form.auth_method.data in k
                }
            except Exception as e:
                msg = 'Failed to invite user: Invalid parameters.'
                user_logger.exception('{}:{}'.format(user_prefix(session), msg))
                flash(msg, 'danger')
                render_template('ui/user_invite.html', form=form)

            chosen_auth_type = form.auth_method.data
            username_field_descr = auth_config[chosen_auth_type]['ui_parameters']['username']
            username = ui_filled_parameters['username']

            user_kw = {
                'username': username,
                'password': generate_password() if username_field_descr.get('generate_password', True) else '',
                'email': username if username_field_descr['type'] == 'email' else '',
                'organization': organization,
                'role': 'member',
                'created_at': datetime.utcnow(),
                'auth': chosen_auth_type,
                'active': username_field_descr.get('active', True),
                'metadata': {}
            }
            logger.debug('User {} from {} invited.'.format(user_kw['username'], user_kw['organization']))
            user = self.kqueen_request('user', 'create', fnargs=(user_kw,))

            # send mail
            notify = username_field_descr.get('notify')
            if notify:
                logger.debug('User {} from {} with id {} will be notified '
                             'through email.'.format(user_kw['username'], user_kw['organization'], user['id']))
                token = generate_confirmation_token(user['email'])
                html = render_template(
                    'ui/email/user_invitation.html',
                    username=user['username'],
                    token=token,
                    organization=user['organization']['name'],
                    year=datetime.utcnow().year
                )
                email = EmailMessage(
                    '[KQueen] Organization invitation',
                    recipients=[user['email']],
                    html=html
                )
                try:
                    email.send()
                except Exception:
                    logger.exception('User {} from {} with id {} will be removed.'.format(user_kw['username'],
                                                                                          user_kw['organization'],
                                                                                          user['id']))
                    self.kqueen_request('user', 'delete', fnargs=(user['id'],))
                    flash('Could not send invitation e-mail, please try again later.', 'danger')
                    return render_template('ui/user_invite.html', form=form)

            logger.debug('User {} from {} created with id {}.'.format(user_kw['username'],
                                                                      user_kw['organization'],
                                                                      user['id']))
            flash('User {} successfully created.'.format(user['username']), 'success')
            return redirect(url_for('ui.organization_manage'))
        return render_template('ui/user_invite.html', form=form)