def used_resources(request): """ view for returning used resources for a given cluster user """ try: cluster_user_id = request.GET['id'] except KeyError: return render_404(request, 'requested user was not found') cu = get_object_or_404(ClusterUser, pk=cluster_user_id) # must be a super user, the user in question, or a member of the group user = request.user if not user.is_superuser: user_type = ContentType.objects.get_for_model(Profile) if cu.real_type_id == user_type.pk: if not Profile.objects.filter(clusteruser_ptr=cu.pk, user=user)\ .exists(): return render_403(request, 'You are not authorized to view this page') else: if not Organization.objects.filter(clusteruser_ptr=cu.pk, \ group__user=user).exists(): return render_403(request, 'You are not authorized to view this page') resources = get_used_resources(cu) return render_to_response("overview/used_resources.html", { 'resources':resources }, context_instance=RequestContext(request))
def recover_failed_deploy(request, cluster_slug, instance): """ Loads a vm that failed to deploy back into the edit form """ cluster = get_object_or_404(Cluster, slug=cluster_slug) vm = get_object_or_404(VirtualMachine, hostname=instance, cluster=cluster) user = request.user if not (user.is_superuser or user.has_any_perms(vm, ['admin','modify']) \ or user.has_perm('admin', cluster)): return render_403(request, 'You do not have permissions to edit \ this virtual machine') # if there is no template, we can't recover. redirect back to the detail # page. its likely that this vm was already fixed if not vm.template_id: return HttpResponseRedirect(reverse('instance-detail', \ args=[cluster_slug, instance])) # create initial data - load this from the template. Not all properties # can be copied directly, some need to be copied explicitly due to naming # conflicts. initial = {'hostname':instance} for k,v in vm.template.__dict__.items(): if v is not None and v != '': initial[k] = v initial['cluster'] = vm.template.cluster_id initial['pnode'] = vm.template.pnode form = NewVirtualMachineForm(request.user, initial=initial) return render_to_response('virtual_machine/create.html', {'form': form}, context_instance=RequestContext(request), )
def missing_ganeti(request): """ View for displaying VirtualMachines missing from the ganeti cluster """ user = request.user if user.is_superuser: clusters = Cluster.objects.all() else: clusters = user.get_objects_any_perms(Cluster, ["admin"]) if not clusters: return render_403(request, "You do not have sufficient privileges") vms = [] for cluster in clusters: vms.extend(cluster.missing_in_ganeti) vms = zip(vms, vms) if request.method == "POST": # process updates if this was a form submission form = VirtualMachineForm(vms, request.POST) if form.is_valid(): # update all selected VirtualMachines data = form.cleaned_data vm_ids = data["virtual_machines"] VirtualMachine.objects.filter(hostname__in=vm_ids).delete() # remove updated vms from the list vms = filter(lambda x: unicode(x[0]) not in vm_ids, vms) else: form = VirtualMachineForm(vms) return render_to_response( "importing/missing.html", {"vms": vms, "form": form}, context_instance=RequestContext(request) )
def vnc(request, cluster_slug, instance): instance = get_object_or_404(VirtualMachine, hostname=instance, \ cluster__slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', instance) or \ user.has_perm('admin', instance.cluster)): return render_403(request, 'You do not have permission to vnc on this') if settings.VNC_PROXY: host = 'localhost' port, password = instance.setup_vnc_forwarding() else: host = instance.info['pnode'] port = instance.info['network_port'] password = '' return render_to_response("virtual_machine/vnc.html", {'instance': instance, 'host': host, 'port': port, 'password': password}, context_instance=RequestContext(request), )
def migrate(request, cluster_slug, instance): """ view used for initiating a Node Migrate job """ cluster = get_object_or_404(Cluster, slug=cluster_slug) vm = get_object_or_404(VirtualMachine, hostname=instance) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin','migrate'])): return render_403(request, "You do not have sufficient privileges") if request.method == 'POST': form = MigrateForm(request.POST) if form.is_valid(): try: job = vm.migrate(form.cleaned_data['mode']) job.load_info() msg = job.info # log information log_action('VM_MIGRATE', user, vm, job) return HttpResponse(json.dumps(msg), mimetype='application/json') except GanetiApiError, e: content = json.dumps({'__all__':[str(e)]}) else: # error in form return ajax response content = json.dumps(form.errors) return HttpResponse(content, mimetype='application/json')
def user_edit(request, user_id=None): user = request.user if not user.is_superuser: return render_403(request, 'Only a superuser may edit a user.') user_edit = get_object_or_404(User, id=user_id) if request.method == "POST": form = UserEditForm(data=request.POST, instance=user_edit) if form.is_valid(): form.save() return HttpResponseRedirect(reverse('user-list')) elif request.method == "DELETE": user_edit.delete() return HttpResponse('1', mimetype='application/json') else: form = UserEditForm(instance=user_edit) keys = SSHKey.objects.filter(user__pk=user_edit.pk).order_by("pk") key_form = SSHKeyForm() return render_to_response("users/edit.html", { 'form':form, 'username':user_edit, 'keyslist': keys, 'key_form': key_form, }, context_instance=RequestContext(request), )
def object_log(request, cluster_slug): """ displays object log for this cluster """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") return list_for_object(request, cluster)
def startup(request, cluster_slug, instance): vm = get_object_or_404(VirtualMachine, hostname=instance, cluster__slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_any_perms(vm, ['admin','power']) or user.has_perm('admin', vm.cluster)): return render_403(request, 'You do not have permission to start up this virtual machine') # superusers bypass quota checks if not user.is_superuser and vm.owner: # check quota quota = vm.cluster.get_quota(vm.owner) if any(quota.values()): used = vm.owner.used_resources(vm.cluster, only_running=True) if quota['ram'] is not None and (used['ram'] + vm.ram) > quota['ram']: msg = 'Owner does not have enough RAM remaining on this cluster to start the virtual machine.' return HttpResponse(json.dumps([0, msg]), mimetype='application/json') if quota['virtual_cpus'] and (used['virtual_cpus'] + vm.virtual_cpus) > quota['virtual_cpus']: msg = 'Owner does not have enough Virtual CPUs remaining on this cluster to start the virtual machine.' return HttpResponse(json.dumps([0, msg]), mimetype='application/json') if request.method == 'POST': try: job = vm.startup() job.load_info() msg = job.info # log information about starting up the machine log_action('VM_START', user, vm, job) except GanetiApiError, e: msg = {'__all__':[str(e)]} return HttpResponse(json.dumps(msg), mimetype='application/json')
def evacuate(request, cluster_slug, host): """ view used for initiating a node evacuate job """ cluster = get_object_or_404(Cluster, slug=cluster_slug) node = get_object_or_404(Node, hostname=host) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin','migrate'])): return render_403(request, "You do not have sufficient privileges") if request.method == 'POST': form = EvacuateForm(cluster, node, request.POST) if form.is_valid(): try: data = form.cleaned_data evacuate_node = data['node'] iallocator_hostname = data['iallocator_hostname'] job = node.evacuate(iallocator_hostname, evacuate_node) job.load_info() msg = job.info # log information log_action('NODE_EVACUATE', user, node, job) return HttpResponse(json.dumps(msg), mimetype='application/json') except GanetiApiError, e: content = json.dumps({'__all__':[str(e)]}) else: # error in form return ajax response content = json.dumps(form.errors) return HttpResponse(content, mimetype='application/json')
def delete(request, cluster_slug, instance): """ Delete a VM. """ user = request.user instance = get_object_or_404(VirtualMachine, cluster__slug=cluster_slug, hostname=instance) # Check permissions. if not ( user.is_superuser or user.has_perm("remove", instance) or user.has_perm("admin", instance) or user.has_perm("admin", instance.cluster) ): return render_403(request, 'You do not have sufficient privileges') if request.method == 'GET': return render_to_response("virtual_machine/delete.html", {'vm': instance}, context_instance=RequestContext(request), ) elif request.method == 'DELETE': # Delete instance jobid = instance.rapi.DeleteInstance(instance.hostname) sleep(2) jobstatus = instance.rapi.GetJobStatus(jobid) instance.delete() return HttpResponse('1', mimetype='application/json') return HttpResponseNotAllowed(["GET","DELETE"])
def role(request, cluster_slug, host): """ view used for setting node role """ cluster = get_object_or_404(Cluster, slug=cluster_slug) node = get_object_or_404(Node, hostname=host) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin','migrate'])): return render_403(request, "You do not have sufficient privileges") if request.method == 'POST': form = RoleForm(request.POST) if form.is_valid(): try: job = node.set_role(form.cleaned_data['role']) job.load_info() msg = job.info # log information log_action('NODE_ROLE_CHANGE', user, node, job) return HttpResponse(json.dumps(msg), mimetype='application/json') except GanetiApiError, e: content = json.dumps({'__all__':[str(e)]}) else: # error in form return ajax response content = json.dumps(form.errors) return HttpResponse(content, mimetype='application/json')
def detail(request, cluster_slug, instance): """ Display details of virtual machine. """ cluster = get_object_or_404(Cluster, slug=cluster_slug) vm = get_object_or_404(VirtualMachine, hostname=instance, cluster=cluster) user = request.user cluster_admin = user.is_superuser or user.has_perm('admin', cluster) admin = cluster_admin or user.has_perm('admin', vm) if admin: remove = True power = True modify = True migrate = True tags = True else: remove = user.has_perm('remove', vm) power = user.has_perm('power', vm) modify = user.has_perm('modify', vm) tags = user.has_perm('tags', vm) migrate = user.has_perm('migrate', cluster) if not (admin or power or remove or modify or tags): return render_403(request, 'You do not have permission to view this cluster\'s details') context = { 'cluster': cluster, 'instance': vm, 'admin':admin, 'cluster_admin':cluster_admin, 'remove':remove, 'power':power, 'modify':modify, 'migrate':migrate, } # check job for pending jobs that should be rendered with a different # detail template. This allows us to reduce the chance that users will do # something strange like rebooting a VM that is being deleted or is not # fully created yet. if vm.pending_delete: template = 'virtual_machine/delete_status.html' elif vm.template: template = 'virtual_machine/create_status.html' if vm.last_job: context['job'] = vm.last_job else: ct = ContentType.objects.get_for_model(vm) context['job'] = Job.objects.order_by('-finished') \ .filter(content_type=ct, object_id=vm.pk)[0] else: template = 'virtual_machine/detail.html' return render_to_response(template, context, context_instance=RequestContext(request), )
def quota(request, cluster_slug, user_id): """ Updates quota for a user """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") if request.method == 'POST': form = QuotaForm(request.POST) if form.is_valid(): data = form.cleaned_data cluster_user = data['user'] if data['delete']: cluster.set_quota(cluster_user) else: quota = cluster.get_quota() same = data['virtual_cpus'] == quota['virtual_cpus'] \ and data['disk']==quota['disk'] \ and data['ram']==quota['ram'] if same: # same as default, set quota to default. cluster.set_quota(cluster_user) else: cluster.set_quota(cluster_user, data) # return updated html cluster_user = cluster_user.cast() url = reverse('cluster-permissions', args=[cluster.slug]) if isinstance(cluster_user, (Profile,)): return render_to_response("cluster/user_row.html", {'object':cluster, 'user':cluster_user.user, 'url':url}) else: return render_to_response("cluster/group_row.html", {'object':cluster, 'group':cluster_user.group, \ 'url':url}) # error in form return ajax response content = json.dumps(form.errors) return HttpResponse(content, mimetype='application/json') if user_id: cluster_user = get_object_or_404(ClusterUser, id=user_id) quota = cluster.get_quota(cluster_user) data = {'user':user_id} if quota: data.update(quota) else: return render_404(request, 'User was not found') form = QuotaForm(data) return render_to_response("cluster/quota.html", \ {'form':form, 'cluster':cluster, 'user_id':user_id}, \ context_instance=RequestContext(request))
def detail(request, cluster_slug, instance): cluster = get_object_or_404(Cluster, slug=cluster_slug) vm = get_object_or_404(VirtualMachine, hostname=instance, cluster=cluster) user = request.user admin = user.is_superuser or user.has_perm('admin', vm) \ or user.has_perm('admin', cluster) if admin: remove = True power = True else: remove = user.has_perm('remove', vm) power = user.has_perm('power', vm) if not (admin or power or remove): return render_403(request, 'You do not have permission to view this cluster\'s details') #TODO Update to use part of the NewVirtualMachineForm in 0.5 release """ if request.method == 'POST': form = InstanceConfigForm(request.POST) if form.is_valid(): data = form.cleaned_data if data['cdrom_type'] == 'none': data['cdrom_image_path'] = 'none' elif data['cdrom_image_path'] != vm.hvparams['cdrom_image_path']: # This should be an http URL if not (data['cdrom_image_path'].startswith('http://') or data['cdrom_image_path'] == 'none'): # Remove this, we don't want them to be able to read local files del data['cdrom_image_path'] vm.set_params(**data) sleep(1) return HttpResponseRedirect(request.path) else: if vm.info: if vm.info['hvparams']['cdrom_image_path']: vm.info['hvparams']['cdrom_type'] = 'iso' else: vm.info['hvparams']['cdrom_type'] = 'none' form = InstanceConfigForm(vm.info['hvparams']) else: form = None """ return render_to_response("virtual_machine/detail.html", { 'cluster': cluster, 'instance': vm, #'configform': form, 'admin':admin, 'remove':remove, 'power':power }, context_instance=RequestContext(request), )
def users(request, cluster_slug): """ Display all of the Users of a Cluster """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") url = reverse('cluster-permissions', args=[cluster.slug]) return view_users(request, cluster, url, template='cluster/users.html')
def user_list(request): user = request.user if not user.is_superuser: return render_403(request, 'Only a superuser may view all users.') users = User.objects.all() return render_to_response("users/list.html", { 'userlist':users }, context_instance=RequestContext(request), )
def object_log(request, cluster_slug, host): """ Display object log for this node """ cluster = get_object_or_404(Cluster, slug=cluster_slug) node = get_object_or_404(Node, hostname=host) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin','migrate'])): return render_403(request, "You do not have sufficient privileges") return list_for_object(request, node)
def nodes(request, cluster_slug): """ Display all nodes in a cluster """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") return render_to_response("node/table.html", \ {'cluster': cluster, 'nodes':cluster.nodes.all()}, \ context_instance=RequestContext(request), )
def object_log(request, cluster_slug, instance): """ Display all of the Users of a VirtualMachine """ cluster = get_object_or_404(Cluster, slug=cluster_slug) vm = get_object_or_404(VirtualMachine, hostname=instance) user = request.user if not (user.is_superuser or user.has_perm('admin', vm) or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") return list_for_object(request, vm)
def clear_ganeti_error(request, pk): """ Clear a single error message """ user = request.user error = get_object_or_404(GanetiError, pk=pk) obj = error.obj # if not a superuser, check permissions on the object itself if not user.is_superuser: if isinstance(obj, (Cluster,)) and not user.has_perm('admin', obj): return render_403(request, "You do not have sufficient privileges") elif isinstance(obj, (VirtualMachine,)): # object is a virtual machine, check perms on VM and on Cluster if not (obj.owner_id == user.get_profile().pk or \ user.has_perm('admin', obj.cluster)): return render_403(request, "You do not have sufficient privileges") # clear the error GanetiError.objects.filter(pk=error.pk).update(cleared=True) return HttpResponse('1', mimetype='application/json')
def clear(request, cluster_slug, job_id): """ Clear a single failed job error message """ user = request.user cluster = get_object_or_404(Cluster, slug=cluster_slug) job = get_object_or_404(Job, cluster__slug=cluster_slug, job_id=job_id) obj = job.obj # if not a superuser, check permissions on the object itself cluster_admin = user.is_superuser or user.has_perm('admin', cluster) if not cluster_admin: if isinstance(obj, (Cluster, Node)): return render_403(request, "You do not have sufficient privileges") elif isinstance(obj, (VirtualMachine,)): # object is a virtual machine, check perms on VM and on Cluster if not (obj.owner_id == user.get_profile().pk \ or user.has_perm('admin', obj) \ or user.has_perm('admin', obj.cluster)): return render_403(request, "You do not have sufficient privileges") # clear the error. Job.objects.filter(pk=job.pk).update(cleared=True) # clear the job from the object, but only if it is the last job. It's # possible another job was started after this job, and the error message # just wasn't cleared. # # XXX object could be none, in which case we dont need to clear its last_job if obj is not None: ObjectModel = obj.__class__ ObjectModel.objects.filter(pk=job.object_id, last_job=job) \ .update(last_job=None, ignore_cache=False) return HttpResponse('1', mimetype='application/json')
def permissions(request, cluster_slug, user_id=None, group_id=None): """ Update a users permissions. This wraps object_permissions.view_permissions() with our custom permissions checks. """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") url = reverse('cluster-permissions', args=[cluster.slug]) return view_permissions(request, cluster, url, user_id, group_id, user_template='cluster/user_row.html', group_template='cluster/group_row.html')
def permissions(request, cluster_slug, instance, user_id=None, group_id=None): """ Update a users permissions. """ vm = get_object_or_404(VirtualMachine, hostname=instance, cluster__slug=cluster_slug) user = request.user if not (user.is_superuser or user.has_perm('admin', vm) or user.has_perm('admin', vm.cluster)): return render_403(request, "You do not have sufficient privileges") url = reverse('vm-permissions', args=[cluster_slug, vm.hostname]) return view_permissions(request, vm, url, user_id, group_id)
def users(request, cluster_slug, instance): """ Display all of the Users of a VirtualMachine """ cluster = get_object_or_404(Cluster, slug=cluster_slug) vm = get_object_or_404(VirtualMachine, hostname=instance) user = request.user if not (user.is_superuser or user.has_perm('admin', vm) or user.has_perm('admin', cluster)): return render_403(request, "You do not have sufficient privileges") url = reverse('vm-permissions', args=[cluster.slug, vm.hostname]) return view_users(request, vm, url)
def user_detail(request, user_id=None): user = request.user if not user.is_superuser: return render_403(request, 'Only a superuser may view a user.') user = get_object_or_404(User, id=user_id) keys = SSHKey.objects.filter(user__pk=user_id).order_by("pk") return render_to_response("users/detail.html", { 'user_detail':user, 'keyslist': keys, }, context_instance=RequestContext(request), )
def cluster_defaults(request): """ Ajax view for retrieving the default cluster options to be set on the NewVirtualMachineForm. """ cluster_id = request.GET.get('cluster_id', None) cluster = get_object_or_404(Cluster, id__exact=cluster_id) user = request.user if not (user.is_superuser or user.has_perm('create_vm', cluster) or user.has_perm('admin', cluster)): return render_403(request, 'You do not have permission to view the default cluster options') content = json.dumps(cluster_default_info(cluster)) return HttpResponse(content, mimetype='application/json')
def reinstall(request, cluster_slug, instance): """ Reinstall a VM. """ user = request.user instance = get_object_or_404(VirtualMachine, cluster__slug=cluster_slug, hostname=instance) # Check permissions. # XXX Reinstalling is somewhat similar to deleting in that you destroy data, # so use that for now. if not ( user.is_superuser or user.has_any_perms(instance, ["remove", "admin"]) or user.has_perm("admin", instance.cluster) ): return render_403(request, 'You do not have sufficient privileges') if request.method == 'GET': return render_to_response("virtual_machine/reinstall.html", {'vm': instance, 'oschoices': cluster_os_list(instance.cluster), 'current_os': instance.operating_system, 'submitted': False}, context_instance=RequestContext(request), ) elif request.method == 'POST': # Reinstall instance if "os" in request.POST: os = request.POST["os"] else: os = instance.operating_system # XXX no_startup=True prevents quota circumventions. possible future solution would be a checkbox # asking whether they want to start up, and check quota here if they do (would also involve # checking whether this VM is already running and subtracting that) job_id = instance.rapi.ReinstallInstance(instance.hostname, os=os, no_startup=True) job = Job.objects.create(job_id=job_id, obj=instance, cluster=instance.cluster) VirtualMachine.objects.filter(id=instance.id).update(last_job=job, ignore_cache=True) # log information log_action('VM_REINSTALL', user, instance, job) return HttpResponseRedirect( reverse('instance-detail', args=[instance.cluster.slug, instance.hostname])) return HttpResponseNotAllowed(["GET","POST"])
def detail(request, cluster_slug): """ Display details of a cluster """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user admin = True if user.is_superuser else user.has_perm('admin', cluster) if not admin: return render_403(request, "You do not have sufficient privileges") return render_to_response("cluster/detail.html", { 'cluster':cluster, 'admin':admin }, context_instance=RequestContext(request), )
def edit(request, cluster_slug=None): """ Edit a cluster """ if cluster_slug: cluster = get_object_or_404(Cluster, slug=cluster_slug) else: cluster = None user = request.user if not (user.is_superuser or (cluster and user.has_perm('admin', cluster))): return render_403(request, "You do not have sufficient privileges") if request.method == 'POST': form = EditClusterForm(request.POST, instance=cluster) if form.is_valid(): cluster = form.save() # TODO Create post signal to import # virtual machines on edit of cluster if cluster.info is None: try: cluster.sync_nodes() cluster.sync_virtual_machines() except GanetiApiError: # ganeti errors here are silently discarded. It's # valid to enter bad info. A user might be adding # info for an offline cluster. pass log_action('EDIT', user, cluster) return HttpResponseRedirect(reverse('cluster-detail', \ args=[cluster.slug])) elif request.method == 'DELETE': cluster.delete() return HttpResponse('1', mimetype='application/json') else: form = EditClusterForm(instance=cluster) return render_to_response("cluster/edit.html", { 'form' : form, 'cluster': cluster, }, context_instance=RequestContext(request), )
def virtual_machines(request, cluster_slug): """ Display all virtual machines in a cluster. Filtered by access the user has permissions for """ cluster = get_object_or_404(Cluster, slug=cluster_slug) user = request.user admin = True if user.is_superuser else user.has_perm('admin', cluster) if not admin: return render_403(request, "You do not have sufficient privileges") vms = cluster.virtual_machines.select_related('cluster').all() vms = render_vms(request, vms) return render_to_response("virtual_machine/table.html", \ {'cluster': cluster, 'vms':vms}, \ context_instance=RequestContext(request))