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