def clear(request, cluster_slug, job_id): """ Remove a job. """ 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)): raise Http403(NO_PRIVS) 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)): raise Http403(NO_PRIVS) # If the job points to an object, and the job is the most recent job on # the object, then clear it from the object. if obj is not None: if obj.last_job == job: obj.last_job = None obj.ignore_cache = False obj.save() # "Clear" the job. With extreme prejudice. job.delete() return HttpResponse('1', mimetype='application/json')
def used_resources(request, rest=False): """ 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(): raise Http403(_('You are not authorized to view this page')) else: if not Organization.objects.filter(clusteruser_ptr=cu.pk, \ group__user=user).exists(): raise Http403(_('You are not authorized to view this page')) resources = get_used_resources(cu.cast()) if rest: return resources else: return render_to_response("ganeti/overview/used_resources.html", { 'resources':resources }, context_instance=RequestContext(request))
def replace_disks(request, cluster_slug, instance): """ view used for initiating a Replace Disks job """ vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin','replace_disks'])): raise Http403(NO_PRIVS) if request.method == 'POST': form = ReplaceDisksForm(vm, request.POST) if form.is_valid(): try: job = form.save() job.refresh() content = json.dumps(job.info) # log information log_action('VM_REPLACE_DISKS', user, vm, job) 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 reparent(request, cluster_slug, instance): """ update a virtual machine to have a new owner """ vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance) user = request.user if not (user.is_superuser or user.has_perm('admin', cluster)): raise Http403( _('You do not have permissions to change the owner of this virtual machine')) if request.method == 'POST': form = ChangeOwnerForm(request.POST) if form.is_valid(): data = form.cleaned_data vm.owner = data['owner'] vm.save(force_update=True) # log information about creating the machine log_action('VM_MODIFY', user, vm) return HttpResponseRedirect(reverse('instance-detail', args=[cluster_slug, instance])) else: form = ChangeOwnerForm() return render_to_response( 'ganeti/virtual_machine/reparent.html', { 'cluster': cluster, 'vm': vm, 'form': form }, context_instance=RequestContext(request), )
def role(request, cluster_slug, host): """ view used for setting node role """ node, cluster = get_node_and_cluster_or_404(cluster_slug, host) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin', 'migrate'])): raise Http403(NO_PRIVS) if request.method == 'POST': form = RoleForm(request.POST) if form.is_valid(): try: job = node.set_role(form.cleaned_data['role']) job.refresh() msg = job.info # log information log_action('NODE_ROLE_CHANGE', user, node) 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 evacuate(request, cluster_slug, host): """ view used for initiating a node evacuate job """ node, cluster = get_node_and_cluster_or_404(cluster_slug, host) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin', 'migrate'])): raise Http403(NO_PRIVS) 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.refresh() 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 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)): raise Http403(NO_PRIVS) return list_for_object(request, cluster)
def migrate(request, cluster_slug, instance): """ view used for initiating a Node Migrate job """ vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin','migrate'])): raise Http403(NO_PRIVS) if request.method == 'POST': form = MigrateForm(request.POST) if form.is_valid(): try: job = vm.migrate(form.cleaned_data['mode']) job.refresh() content = json.dumps(job.info) # log information log_action('VM_MIGRATE', user, vm, job) 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 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)): raise Http403(NO_PRIVS) 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, None) 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( "ganeti/cluster/user_row.html", { 'object': cluster, 'user_detail': cluster_user.user, 'url': url }, context_instance=RequestContext(request)) else: return render_to_response( "ganeti/cluster/group_row.html", { 'object': cluster, 'group': cluster_user.group, 'url': url }, context_instance=RequestContext(request)) # 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("ganeti/cluster/quota.html", { 'form': form, 'cluster': cluster, 'user_id': user_id }, 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: raise Http403(NO_PRIVS) vms = [] for cluster in clusters: for vm in cluster.missing_in_ganeti: vms.append((vm, vm)) 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'] q = VirtualMachine.objects.filter(hostname__in=vm_ids) missing = defaultdict(lambda:0) for i in q: missing[ i.cluster_id ] -= 1 q.delete() # remove updated vms from the list vms = filter(lambda x: unicode(x[0]) not in vm_ids, vms) else: form = VirtualMachineForm(vms) vms = {} for cluster in clusters: for vm in cluster.missing_in_ganeti: vms[vm] = (cluster.hostname, vm) vmhostnames = vms.keys() vmhostnames.sort() vms_tuplelist = [] for i in vmhostnames: vms_tuplelist.append((i, vms[i][0], vms[i][1])) vms = vms_tuplelist return render_to_response("ganeti/importing/missing.html", { 'vms': vms, 'form':form, }, context_instance=RequestContext(request), )
def get_queryset(self): self.cluster = get_object_or_404(Cluster, slug=self.kwargs["cluster_slug"]) user = self.request.user admin = user.is_superuser or user.has_perm("admin", self.cluster) if not admin: raise Http403(NO_PRIVS) return self.cluster.virtual_machines.select_related("cluster").all()
def orphans(request): """ displays list of orphaned VirtualMachines, i.e. VirtualMachines without an owner. """ user = request.user if user.is_superuser: clusters = Cluster.objects.all() else: clusters = user.get_objects_any_perms(Cluster, ['admin']) if not clusters: raise Http403(NO_PRIVS) vms_with_cluster = VirtualMachine.objects.filter(owner=None, cluster__in=clusters) \ .order_by('hostname').values_list('id','hostname','cluster') if request.method == 'POST': # strip cluster from vms vms = [(i[0], i[1]) for i in vms_with_cluster] # process updates if this was a form submission form = OrphanForm(vms, request.POST) if form.is_valid(): # update all selected VirtualMachines data = form.cleaned_data owner = data['owner'] vm_ids = data['virtual_machines'] # update the owner and save the vm. This isn't the most efficient # way of updating the VMs but we would otherwise need to group them # by cluster orphaned = defaultdict(lambda:0) for id in vm_ids: vm = VirtualMachine.objects.get(id=id) vm.owner = owner vm.save() orphaned[vm.cluster_id] -= 1 # remove updated vms from the list vms_with_cluster = [i for i in vms_with_cluster if unicode(i[0]) not in vm_ids] else: # strip cluster from vms form = ImportForm([(i[0], i[1]) for i in vms_with_cluster]) clusterdict = {} for i in clusters: clusterdict[i.id] = i.hostname vms = [ (i[0], clusterdict[i[2]], i[1]) for i in vms_with_cluster ] return render_to_response("ganeti/importing/orphans.html", { 'vms': vms, 'form':form, }, context_instance=RequestContext(request), )
def create_instance_from_template(request, cluster_slug, template): """ View to create a new instance from a given template. Post method is handled by virtual_machine create view. """ user = request.user if cluster_slug: cluster = get_object_or_404(Cluster, slug=cluster_slug) if not ( user.is_superuser or user.has_perm('admin', cluster) or user.has_perm('create_vm', cluster) ): raise Http403(NO_PRIVS) vm_template = get_object_or_404(VirtualMachineTemplate, template_name=template, cluster__slug=cluster_slug) # Work with vm_template vars here initial = dict( cluster=vm_template.cluster_id, ) initial.update(vars(vm_template)) # nics and disks need to be replaced by expected # form fields of disk_size_#, nic_mode_#, and nic_link_# ignore_fields = ('disks', 'nics', '_state', 'description') for field in ignore_fields: del initial[field] # Initialize mutliple disks initial['disk_count'] = len(vm_template.disks) if initial['disk_count'] == 0: initial['disk_count'] = 1 for i,disk in enumerate(vm_template.disks): initial['disk_size_%s'%i] = disk['size'] # initialize multiple nics initial['nic_count'] = len(vm_template.nics) if initial['nic_count'] == 0: initial['nic_count'] = 1 for i,nic in enumerate(vm_template.nics): initial['nic_mode_%s'%i] = nic['mode'] initial['nic_link_%s'%i] = nic['link'] form = NewVirtualMachineForm(user, initial=initial) cluster_defaults = {} #cluster_default_info(cluster) return render_to_response('ganeti/virtual_machine/create.html', { 'form':form, 'cluster_defaults':json.dumps(cluster_defaults), }, context_instance = RequestContext(request) )
def get_queryset(self): self.node, self.cluster = get_node_and_cluster_or_404( self.kwargs["cluster_slug"], self.kwargs["host"]) user = self.request.user if not (user.is_superuser or user.has_any_perms(self.cluster, ["admin", "migrate"])): raise Http403(NO_PRIVS) return self.node.primary_vms.all()
def importing(request): """ View that loads main importing view """ user = request.user if not user.is_superuser or user.get_objects_any_perms(Cluster, ['admin']): raise Http403(NO_PRIVS) return render_to_response('ganeti/importing/nodes/main.html', context_instance=RequestContext(request))
def modify(request, cluster_slug, instance): vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance) user = request.user if not (user.is_superuser or user.has_any_perms(vm, ['admin','modify']) or user.has_perm('admin', cluster)): raise Http403( 'You do not have permissions to edit this virtual machine') hv = get_hypervisor(vm) if hv == 'kvm': hv_form = KvmModifyVirtualMachineForm template = 'ganeti/virtual_machine/edit_kvm.html' elif hv == 'xen-pvm': hv_form = PvmModifyVirtualMachineForm template = 'ganeti/virtual_machine/edit_pvm.html' elif hv == 'xen-hvm': hv_form = HvmModifyVirtualMachineForm template = 'ganeti/virtual_machine/edit_hvm.html' else: hv_form = None template = 'ganeti/virtual_machine/edit_base.html' # XXX no matter what, we're gonna call hv_form() and die. Let's do it # louder than usual. >:3 msg = "Hey, guys, implementation error in views/vm.py:modify" raise RuntimeError(msg) if request.method == 'POST': form = hv_form(vm, request.POST) form.owner = vm.owner form.vm = vm form.cluster = cluster if form.is_valid(): data = form.cleaned_data request.session['edit_form'] = data request.session['edit_vm'] = vm.id return HttpResponseRedirect( reverse('instance-modify-confirm', args=[cluster.slug, vm.hostname])) elif request.method == 'GET': if 'edit_form' in request.session and vm.id == request.session['edit_vm']: form = hv_form(vm, request.session['edit_form']) else: form = hv_form(vm) return render_to_response(template, { 'cluster': cluster, 'instance': vm, 'form': form, }, context_instance=RequestContext(request), )
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): raise Http403(NO_PRIVS) 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)): raise Http403(NO_PRIVS) # clear the error GanetiError.objects.filter(pk=error.pk).update(cleared=True) return HttpResponse('1', mimetype='application/json')
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: raise Http403(NO_PRIVS) nodes = [] for cluster in clusters: for node in cluster.nodes_missing_in_ganeti: nodes.append((node, node)) if request.method == 'POST': # process updates if this was a form submission form = NodeForm(nodes, request.POST) if form.is_valid(): # update all selected Nodes data = form.cleaned_data node_ids = data['nodes'] Node.objects.filter(hostname__in=node_ids).delete() else: form = NodeForm(nodes) nodes = {} for cluster in clusters: for node in cluster.nodes_missing_in_ganeti: nodes[node] = (cluster.hostname, node) node_hostnames = nodes.keys() node_hostnames.sort() node_tuple_list = [] for i in node_hostnames: node_tuple_list.append((i, nodes[i][0], nodes[i][1])) nodes = node_tuple_list return render_to_response( "ganeti/importing/nodes/missing.html", { 'nodes': nodes, 'form': form, }, 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))): raise Http403(NO_PRIVS) 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' if cluster_slug else 'CREATE', 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( "ganeti/cluster/edit.html", { 'form': form, 'cluster': cluster, }, context_instance=RequestContext(request), )
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)): raise Http403(NO_PRIVS) url = reverse('vm-permissions', args=[cluster_slug, vm.hostname]) return view_permissions(request, vm, url, user_id, group_id)
def get_object(self): user = self.request.user vm, cluster = get_vm_and_cluster_or_404(self.kwargs["cluster_slug"], self.kwargs["instance"]) if not ( user.is_superuser or user.has_any_perms(vm, ["remove", "admin"]) or user.has_perm("admin", cluster) ): raise Http403(NO_PRIVS) self.vm = vm self.cluster = cluster return vm
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) hypervisor = request.GET.get('hypervisor', None) cluster = get_object_or_404(Cluster, id__exact=cluster_id) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin', 'create_vm'])): raise Http403(_('You do not have permission to view the default cluster options')) content = json.dumps(cluster_default_info(cluster, hypervisor)) return HttpResponse(content, mimetype='application/json')
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)): raise Http403(NO_PRIVS) url = reverse('cluster-permissions', args=[cluster.slug]) return view_users(request, cluster, url, template='ganeti/cluster/users.html')
def object_log(request, cluster_slug, host, rest=False): """ Display object log for this node """ node, cluster = get_node_and_cluster_or_404(cluster_slug, host) user = request.user if not (user.is_superuser or user.has_any_perms(cluster, ['admin', 'migrate'])): if not rest: raise Http403(NO_PRIVS) else: return {'error': NO_PRIVS} return list_for_object(request, node, rest)
def object_log(request, cluster_slug, instance, rest=False): """ 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)): raise Http403(NO_PRIVS) if rest: return list_for_object(request, vm, True) else: return list_for_object(request, vm)
def users(request, cluster_slug, instance, rest=False): """ Display all of the Users of a VirtualMachine """ vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance) user = request.user if not (user.is_superuser or user.has_perm('admin', vm) or user.has_perm('admin', cluster)): if rest: return {'msg': NO_PRIVS, 'code': 403} else: raise Http403(NO_PRIVS) url = reverse('vm-permissions', args=[cluster.slug, vm.hostname]) return view_users(request, vm, url, rest=rest)
def create_template_from_instance(request, cluster_slug, instance): """ View to create a new template from a given instance. Post method is handled by template create view. """ user = request.user if cluster_slug: cluster = get_object_or_404(Cluster, slug=cluster_slug) if not ( user.is_superuser or user.has_perm('admin', cluster) or user.has_perm('create_vm', cluster) ): raise Http403(NO_PRIVS) vm = get_object_or_404(VirtualMachine, hostname=instance, cluster__slug=cluster_slug) # Work with vm vars here info = vm.info links = info['nic.links'] modes = info['nic.modes'] sizes = info['disk.sizes'] initial = dict( template_name=instance, cluster=cluster.id, start=info['admin_state'], disk_template=info['disk_template'], disk_type=info['hvparams']['disk_type'], nic_type=info['hvparams']['nic_type'], os=vm.operating_system, vcpus=vm.virtual_cpus, memory=vm.ram, disks=[{'size':size} for size in sizes], nics=[{'mode':mode, 'link':link} for mode, link in zip(modes, links)], nic_count=len(links), ) form = VirtualMachineTemplateForm(user=user, initial=initial) return render_to_response('ganeti/vm_template/create.html', { 'form':form, 'from_vm':vm, 'action':reverse('template-create'), }, context_instance = RequestContext(request) )
def reinstall(request, cluster_slug, instance): """ Reinstall a VM. """ user = request.user instance, cluster = get_vm_and_cluster_or_404(cluster_slug, 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", cluster) ): raise Http403(NO_PRIVS) if request.method == 'GET': return render_to_response( "ganeti/virtual_machine/reinstall.html", {'vm': instance, 'oschoices': cluster_os_list(cluster), 'current_os': instance.operating_system, 'cluster':cluster}, 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=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=[cluster.slug, instance.hostname]))
def cluster_options(request): """ Ajax view for retrieving node and operating system choices for a given cluster. """ 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_any_perms(cluster, ['admin', 'create_vm'])): raise Http403( _('You do not have permissions to view this cluster')) oslist = cluster_os_list(cluster) nodes = [str(h) for h in cluster.nodes.values_list('hostname', flat=True)] content = json.dumps({'nodes':nodes, 'os':oslist}) return HttpResponse(content, mimetype='application/json')
def recover_failed_deploy(request, cluster_slug, instance): """ Loads a vm that failed to deploy back into the edit form """ vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance) user = request.user if not (user.is_superuser or user.has_any_perms(vm, ['admin','modify']) \ or user.has_perm('admin', cluster)): raise Http403(_('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 initial['owner'] = vm.owner_id if "disks" in initial: for i, disk in enumerate(initial['disks']): initial['disk_size_%s' % i] = "%dMB" % disk["size"] if "nics" in initial: for i, nic in enumerate(initial['nics']): initial['nic_link_%s' % i] = nic['link'] initial['nic_mode_%s' % i] = nic['mode'] form = NewVirtualMachineForm(request.user, initial=initial) cluster_defaults = cluster_default_info(cluster) return render_to_response('ganeti/virtual_machine/create.html', {'form': form, 'cluster_defaults':json.dumps(cluster_defaults)}, context_instance=RequestContext(request), )