def reboot_vm(vm_id, type): """ Reboot VM """ clients.user_clients(flask.g.tenant_id).compute.servers.reboot(vm_id, type) flask.flash('Virtual machine rebooted successfully.', 'success') return flask.redirect(views_utils.get_next_url())
def remove_vm(vm_id): ''' Delete VM. No checks because currently OpenStack performs authorization checks. ''' clients.user_clients(flask.g.tenant_id).compute.servers.delete(vm_id) flask.flash('Delete operation requested for VM.', 'success') # NOT(apugachev)openstack can be slow; make a note to reflect the fact # of removing the VM on the next step if 'removed_vms' not in flask.session: flask.session['removed_vms'] = [] flask.session['removed_vms'].append(vm_id) return flask.redirect(views_utils.get_next_url())
def new(): form = forms.CreateSSHKey() if form.validate_on_submit(): create = clients.user_clients(flask.g.tenant_id).nova.keypairs.create try: if form.public_key.data: keypair = create(form.name.data, form.public_key.data) else: keypair = create(form.name.data) except HttpException as error: flask.flash(error.message, 'error') return {'form': form} if hasattr(keypair, 'private_key'): return Response(keypair.private_key, mimetype='application/binary', headers={ 'Content-Disposition': 'attachment; filename=%s.pem' % re.sub('[^-a-zA-Z0-9]', '_', keypair.name) }) flask.flash('Keypair was successfully created', 'success') return flask.redirect(flask.url_for('.index')) return { 'form': form, 'title': bp.name.replace('_', ' '), 'subtitle': 'Add new SSH key' }
def show_tenant(): """ List VMs for the project """ c = clients.user_clients(flask.g.tenant_id) servers = c.compute.servers.list(detailed=True) vms_data = [s._info for s in servers] vms_data = sorted(vms_data, key=lambda x: x['name']) p = pagination.Pagination(vms_data) data = p.slice(vms_data) user_id2name = {} uuid_regex = re.compile( r'[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}') for x in data: user_id = x['user_id'] try: x['user_id'] = user_id2name[user_id] pass except KeyError: if user_id.isdigit() or uuid_regex.match(user_id): try: user = clients.admin_clients().keystone.users.get(user_id) user_id2name[user_id] = user.name x['user_id'] = user.name except: pass return { 'vms': data, 'pagination': p, 'title': 'Virtual Machines', 'subtitle': 'List of virtual machines' }
def get_images_list(): """Return list of images visible for given condigions. If g.tenant_id is not set it is admin blueprint. We have to show only images owned by systenant, which are also public (can be protected as well (we set it so, but other tools can change this attribute or set it to a wrong value from the beginning). If g.tenant_id is set it is project blueprint. We have to show the same images as for admin blueprint _and_ images owned by current project (attribute "owner" must be equal to g.tenant_id) no matter if image is public/protected. NOTE(apugachev): Currently for some reason Glance does not return list of images owned by tenant with id '1' even if they are public - if they are requested through token issued for some other project then '1'. That's why we combine image lists here in case if list is for project. """ admin_id = clients.get_systenant_id() is_global = lambda x: x.owner == admin_id and x.is_public result = filter( is_global, clients.admin_clients().glance.images.list()) if getattr(flask.g, 'tenant_id', None): result.extend(filter( lambda x: x.owner == flask.g.tenant_id and x not in result, clients.user_clients(flask.g.tenant_id).glance.images.list())) result = sorted(result, key=lambda x: x.name) return result
def get_console_output(vm_id): console = clients.user_clients(flask.g.tenant_id).compute.servers.get_console_output(vm_id) console = console.split('\n') return { 'title': 'Console output', 'log': console }
def add_rule(security_group_id): form = forms.SecurityGroupRuleAdd(security_group_id=security_group_id) if form.validate_on_submit(): try: group_id = int(form.group_id.data) cidr = None except ValueError: group_id = None cidr = form.cidr.data try: (clients.user_clients( flask.g.tenant_id).compute.security_group_rules.create( security_group_id, form.ip_protocol.data, form.from_port.data, form.to_port.data, cidr, group_id)) except exceptions.HttpException as ex: flask.flash(ex.message, 'error') else: flask.flash('Security group rule successfully added', 'success') return flask.redirect( flask.url_for('.show', security_group_id=security_group_id)) return { 'form': form, 'security_group_id': security_group_id, 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'Add new rule' }
def add_rule(security_group_id): form = forms.SecurityGroupRuleAdd(security_group_id=security_group_id) if form.validate_on_submit(): try: group_id = int(form.group_id.data) cidr = None except ValueError: group_id = None cidr = form.cidr.data try: (clients.user_clients(flask.g.tenant_id). compute.security_group_rules.create( security_group_id, form.ip_protocol.data, form.from_port.data, form.to_port.data, cidr, group_id)) except exceptions.HttpException as ex: flask.flash(ex.message, 'error') else: flask.flash('Security group rule successfully added', 'success') return flask.redirect(flask.url_for( '.show', security_group_id=security_group_id)) return { 'form': form, 'security_group_id': security_group_id, 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'Add new rule' }
def new(): form = forms.CreateSSHKey() if form.validate_on_submit(): create = clients.user_clients(flask.g.tenant_id).nova.keypairs.create try: if form.public_key.data: keypair = create(form.name.data, form.public_key.data) else: keypair = create(form.name.data) except HttpException as error: flask.flash(error.message, 'error') return {'form': form} if hasattr(keypair, 'private_key'): return Response( keypair.private_key, mimetype='application/binary', headers={'Content-Disposition': 'attachment; filename=%s.pem' % re.sub('[^-a-zA-Z0-9]', '_', keypair.name)}) flask.flash('Keypair was successfully created', 'success') return flask.redirect(flask.url_for('.index')) return { 'form': form, 'title': bp.name.replace('_', ' '), 'subtitle': 'Add new SSH key' }
def spawn_vm(): ''' Spawn VM in the tenant. ''' c = clients.user_clients(flask.g.tenant_id) images_list = images.get_images_list() flavors = c.compute.flavors.list() security_groups = c.compute.security_groups.list() key_pairs = c.compute.keypairs.list() form = forms.get_spawn_form(images_list, flavors, security_groups, key_pairs)() if form.validate_on_submit(): kw = dict(security_groups=form.security_groups.data) if form.keypair.data: kw['key_name'] = form.keypair.data if form.password.data: kw['admin_pass'] = form.password.data c.nova.servers.create(form.name.data, form.image.data, form.flavor.data, **kw) flask.flash('Virtual machine spawned.', 'success') return flask.redirect( flask.url_for('.show_tenant', tenant_id=flask.g.tenant_id)) return { 'form': form, 'tenant': flask.g.tenant, 'images': json.dumps([x._info for x in images_list]), 'flavors': json.dumps([x._info for x in flavors]), 'title': 'Virtual Machines', 'subtitle': 'Spawn new virtual machine' }
def get_images_list(): """Return list of images visible for given condigions. If g.tenant_id is not set it is admin blueprint. We have to show only images owned by systenant, which are also public (can be protected as well (we set it so, but other tools can change this attribute or set it to a wrong value from the beginning). If g.tenant_id is set it is project blueprint. We have to show the same images as for admin blueprint _and_ images owned by current project (attribute "owner" must be equal to g.tenant_id) no matter if image is public/protected. NOTE(apugachev): Currently for some reason Glance does not return list of images owned by tenant with id '1' even if they are public - if they are requested through token issued for some other project then '1'. That's why we combine image lists here in case if list is for project. """ admin_id = clients.get_systenant_id() is_global = lambda x: x.owner == admin_id and x.is_public result = filter(is_global, clients.admin_clients().glance.images.list()) if getattr(flask.g, 'tenant_id', None): result.extend( filter( lambda x: x.owner == flask.g.tenant_id and x not in result, clients.user_clients(flask.g.tenant_id).glance.images.list())) result = sorted(result, key=lambda x: x.name) return result
def __init__(self, *args, **kwargs): security_group_id = kwargs.pop('security_group_id') super(SecurityGroupRuleAdd, self).__init__(*args, **kwargs) security_groups = (clients.user_clients(flask.g.tenant_id).compute. security_groups.list()) self.group_id.choices = [('<None>', '')] + [(str(sg.id), sg.name) for sg in security_groups if str(sg.id) != str(security_group_id)]
def index(): c = clients.user_clients(flask.g.tenant_id) context = { 'keys': c.nova.keypairs.list(), 'delete_form': forms.DeleteForm(), 'title': bp.name.replace('_', ' '), 'subtitle': 'List of SSH keys' } return context
def delete_rule(security_group_id, rule_id): form = forms.DeleteForm() if form.validate_on_submit(): (clients.user_clients(flask.g.tenant_id). compute.security_group_rules.delete(rule_id)) flask.flash('Security group rule successfully deleted', 'success') else: flask.flash('Invalid form', 'error') return flask.redirect(flask.url_for( '.show', security_group_id=security_group_id))
def delete_rule(security_group_id, rule_id): form = forms.DeleteForm() if form.validate_on_submit(): (clients.user_clients( flask.g.tenant_id).compute.security_group_rules.delete(rule_id) ) flask.flash('Security group rule successfully deleted', 'success') else: flask.flash('Invalid form', 'error') return flask.redirect( flask.url_for('.show', security_group_id=security_group_id))
def billing_details(tenant_id): ''' Present billing info for tenant. ''' tenant_list = clients.user_clients( clients.get_systenant_id()).identity_admin.tenants.list() tenant = filter(lambda x: x.id == tenant_id, tenant_list) if not tenant: flask.abort(404) tenant = tenant[0] return generic_billing.generic_billing( tenant, flask.g.user, tenant_list)
def show(security_group_id, add_form=None): """Present details page for single security group object. """ security_group = (clients.user_clients(flask.g.tenant_id).compute. security_groups.get(security_group_id)) return { 'security_group': security_group, 'add_form': add_form or forms.SecurityGroupRuleAdd( security_group_id=security_group_id), 'delete_form': forms.DeleteForm(), 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'Security group details', }
def delete(name): try: keypair = filter( lambda x: x.name == name, clients.user_clients(flask.g.tenant_id).nova.keypairs.list())[0] except IndexError: flask.abort(404) form = forms.DeleteForm() if form.validate_on_submit(): keypair.delete() flask.flash('Keypair removed.', 'success') return flask.redirect(flask.url_for('.index')) return {'keypair': keypair, 'form': form}
def delete(security_group_id): form = forms.DeleteForm() if form.validate_on_submit(): try: (clients.user_clients( flask.g.tenant_id).compute.security_groups.delete( security_group_id)) except exceptions.HttpException as ex: flask.flash(ex.message, 'error') else: flask.flash('Security group successfully deleted', 'success') else: flask.flash('Invalid form', 'error') return flask.redirect(flask.url_for('.index'))
def delete(security_group_id): form = forms.DeleteForm() if form.validate_on_submit(): try: (clients.user_clients(flask.g.tenant_id). compute.security_groups.delete(security_group_id)) except exceptions.HttpException as ex: flask.flash(ex.message, 'error') else: flask.flash('Security group successfully deleted', 'success') else: flask.flash('Invalid form', 'error') return flask.redirect(flask.url_for('.index'))
def index(): """List security groups. """ security_groups = (clients.user_clients(flask.g.tenant_id).compute. security_groups.list()) p = pagination.Pagination(security_groups) data = p.slice(security_groups) return { 'security_groups': data, 'pagination': p, 'delete_form': forms.DeleteForm(), 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'List of existing security groups' }
def index(): """List security groups. """ security_groups = (clients.user_clients( flask.g.tenant_id).compute.security_groups.list()) p = pagination.Pagination(security_groups) data = p.slice(security_groups) return { 'security_groups': data, 'pagination': p, 'delete_form': forms.DeleteForm(), 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'List of existing security groups' }
def delete(name): try: keypair = filter( lambda x: x.name == name, clients.user_clients(flask.g.tenant_id).nova.keypairs.list())[0] except IndexError: flask.abort(404) form = forms.DeleteForm() if form.validate_on_submit(): keypair.delete() flask.flash('Keypair removed.', 'success') return flask.redirect(flask.url_for('.index')) return { 'keypair': keypair, 'form': form }
def show(security_group_id, add_form=None): """Present details page for single security group object. """ security_group = (clients.user_clients( flask.g.tenant_id).compute.security_groups.get(security_group_id)) return { 'security_group': security_group, 'add_form': add_form or forms.SecurityGroupRuleAdd(security_group_id=security_group_id), 'delete_form': forms.DeleteForm(), 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'Security group details', }
def new(): """Create security_group. """ form = forms.SecurityGroupCreate() if form.validate_on_submit(): try: security_group = (clients.user_clients(flask.g.tenant_id). compute.security_groups.create( name=form.name.data, description=form.description.data)) except exceptions.HttpException as ex: flask.flash(ex.message, 'error') else: flask.flash('Security group %s created.' % form.name.data, 'success') return flask.redirect(flask.url_for('.index')) return { 'form': form, 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'Add new security group' }
def new(): """Create security_group. """ form = forms.SecurityGroupCreate() if form.validate_on_submit(): try: security_group = (clients.user_clients( flask.g.tenant_id).compute.security_groups.create( name=form.name.data, description=form.description.data)) except exceptions.HttpException as ex: flask.flash(ex.message, 'error') else: flask.flash('Security group %s created.' % form.name.data, 'success') return flask.redirect(flask.url_for('.index')) return { 'form': form, 'title': bp.name.replace('global_', '').replace('_', ' ').capitalize(), 'subtitle': 'Add new security group' }
def _concentrate_resources(resources, tenant_id): ''' For every orphan resource add verbose name and brief info url. ''' client_set = clients.user_clients(tenant_id) processors = ( ('nova/instance', client_set.compute.servers.list( search_opts={'all_tenants': 1}), 'project_views.show_vm', 'vm_id'), ('glance/image', client_set.image.images.list(), 'project_images.show', 'image_id'), ) def process(objs, info, endpoint, arg): ref = dict(((x['name'], x) for x in objs)) result = {} # some objs will lack detailed info. it is not a problem # it is solved during presentation to user informative = [x._info for x in info if unicode(x.id) in ref.keys()] for x in informative: actual = copy.deepcopy(ref[unicode(x['id'])]) actual['detailed'] = x actual['detailed']['focus_url'] = flask.url_for( endpoint, **{arg: x['id']}) result[(actual['id'], actual['rtype'])] = actual return result def filter_type(resource_type): return filter( lambda x: x['rtype'] == resource_type and x['parent_id'] is None, resources ) d = {} for rtype, model, endpoint, arg in processors: d.update(process(filter_type(rtype), model, endpoint, arg)) return map( lambda x: d.get((x['id'], x['rtype']), x), resources)
def spawn_vm(): ''' Spawn VM in the tenant. ''' c = clients.user_clients(flask.g.tenant_id) images_list = images.get_images_list() flavors = c.compute.flavors.list() security_groups = c.compute.security_groups.list() key_pairs = c.compute.keypairs.list() form = forms.get_spawn_form(images_list, flavors, security_groups, key_pairs)() if form.validate_on_submit(): kw = dict(security_groups=form.security_groups.data) if form.keypair.data: kw['key_name'] = form.keypair.data if form.password.data: kw['admin_pass'] = form.password.data c.nova.servers.create(form.name.data, form.image.data, form.flavor.data, **kw) flask.flash('Virtual machine spawned.', 'success') return flask.redirect(flask.url_for( '.show_tenant', tenant_id=flask.g.tenant_id)) return { 'form': form, 'tenant': flask.g.tenant, 'images': json.dumps([x._info for x in images_list]), 'flavors': json.dumps([x._info for x in flavors]), 'title': 'Virtual Machines', 'subtitle': 'Spawn new virtual machine' }
def _concentrate_resources(resources, tenant_id): ''' For every orphan resource add verbose name and brief info url. ''' client_set = clients.user_clients(tenant_id) processors = ( ('nova/instance', client_set.compute.servers.list(search_opts={'all_tenants': 1}), 'project_views.show_vm', 'vm_id'), ('glance/image', client_set.image.images.list(), 'project_images.show', 'image_id'), ) def process(objs, info, endpoint, arg): ref = dict(((x['name'], x) for x in objs)) result = {} # some objs will lack detailed info. it is not a problem # it is solved during presentation to user informative = [x._info for x in info if unicode(x.id) in ref.keys()] for x in informative: actual = copy.deepcopy(ref[unicode(x['id'])]) actual['detailed'] = x actual['detailed']['focus_url'] = flask.url_for( endpoint, **{arg: x['id']}) result[(actual['id'], actual['rtype'])] = actual return result def filter_type(resource_type): return filter( lambda x: x['rtype'] == resource_type and x['parent_id'] is None, resources) d = {} for rtype, model, endpoint, arg in processors: d.update(process(filter_type(rtype), model, endpoint, arg)) return map(lambda x: d.get((x['id'], x['rtype']), x), resources)
def create(): """Create image via Glance API. - validates form - creates image via API - cleans up tmp file - returns successful message New image uploaded in tenant systenant publicly if blueprint is in admin context. Otherwise image uploaded in the tenant used for the project and is not public. With default Glance settings (owner means tenant) this would restrict access to the image for members of the project. During the process of upload ongoing progress is memcached. TODO(apugachev): remove from templ location images older then X hours """ def create_image(uploaded_filename, name, container, disk_format, kernel_id=None, ramdisk_id=None): tenant_id = get_tenant_id() properties = { 'image_state': 'available', 'project_id': tenant_id, 'architecture': 'x86_64', 'image_location': 'local' } if kernel_id is not None: properties['kernel_id'] = kernel_id if ramdisk_id is not None: properties['ramdisk_id'] = ramdisk_id uploaded_filename = focus.files_uploads.path(uploaded_filename) try: kwargs = { 'name': name, 'container_format': container, 'disk_format': disk_format, 'data': open(uploaded_filename), 'is_public': not hasattr(flask.g, 'tenant_id'), 'properties': properties, } except IOError, e: e.public_message = 'Uploaded file is missing' flask.current_app.logger.error(str(e)) raise try: user_clients = clients.user_clients(tenant_id) callback = ProgressRecorder( user_clients.http_client, os.path.basename(uploaded_filename), os.fstat(kwargs['data'].fileno()).st_size) with callback: img = user_clients.image.images.create(**kwargs) except RuntimeError as e: flask.flash(e.message, 'error') else: flask.flash( 'Image with name %s registered.' % img.name, 'success') return img.id finally: try: kwargs['data'].close() os.unlink(uploaded_filename) except OSError: # nothing to do, temporal file was removed by something pass
def get_vnc_console(vm_id): vnc = (clients.user_clients( flask.g.tenant_id).compute.servers.get_vnc_console( vm_id, flask.current_app.config['VNC_CONSOLE_TYPE'])) return flask.redirect(vnc['console']['url'])
def create(): """Create image via Glance API. - validates form - creates image via API - cleans up tmp file - returns successful message New image uploaded in tenant systenant publicly if blueprint is in admin context. Otherwise image uploaded in the tenant used for the project and is not public. With default Glance settings (owner means tenant) this would restrict access to the image for members of the project. During the process of upload ongoing progress is memcached. TODO(apugachev): remove from templ location images older then X hours """ def create_image(uploaded_filename, name, container, disk_format, kernel_id=None, ramdisk_id=None): tenant_id = get_tenant_id() properties = { 'image_state': 'available', 'project_id': tenant_id, 'architecture': 'x86_64', 'image_location': 'local' } if kernel_id is not None: properties['kernel_id'] = kernel_id if ramdisk_id is not None: properties['ramdisk_id'] = ramdisk_id uploaded_filename = focus.files_uploads.path(uploaded_filename) try: kwargs = { 'name': name, 'container_format': container, 'disk_format': disk_format, 'data': open(uploaded_filename), 'is_public': not hasattr(flask.g, 'tenant_id'), 'properties': properties, } except IOError, e: e.public_message = 'Uploaded file is missing' flask.current_app.logger.error(str(e)) raise try: user_clients = clients.user_clients(tenant_id) callback = ProgressRecorder( user_clients.http_client, os.path.basename(uploaded_filename), os.fstat(kwargs['data'].fileno()).st_size) with callback: img = user_clients.image.images.create(**kwargs) except RuntimeError as e: flask.flash(e.message, 'error') else: flask.flash('Image with name %s registered.' % img.name, 'success') return img.id finally: try: kwargs['data'].close() os.unlink(uploaded_filename) except OSError: # nothing to do, temporal file was removed by something pass
def get_console_output(vm_id): console = clients.user_clients( flask.g.tenant_id).compute.servers.get_console_output(vm_id) console = console.split('\n') return {'title': 'Console output', 'log': console}
def get_vnc_console(vm_id): vnc = (clients.user_clients(flask.g.tenant_id).compute.servers. get_vnc_console(vm_id, flask.current_app.config['VNC_CONSOLE_TYPE'])) return flask.redirect(vnc['console']['url'])