Example #1
0
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 PermissionDenied(
            '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,
         'balloon': has_balloonmem(cluster)
         },
        context_instance=RequestContext(request),
    )
Example #2
0
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 PermissionDenied(
            '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,
            'balloon': has_balloonmem(cluster)
        },
        context_instance=RequestContext(request),
    )
Example #3
0
def instance_to_template(vm, name):
    """
    Create, save, and return a VM template representing all of the information
    in the VM instance.

    The name is given to the template to distinguish it from other templates.
    """

    template = VirtualMachineTemplate()

    # Basic stuff first.
    template.template_name = name
    template.description = ""
    template.cluster = vm.cluster
    template.start = vm.info["admin_state"]
    template.disk_template = vm.info["disk_template"]
    template.os = vm.operating_system

    # Backend parameters.
    template.vcpus = vm.virtual_cpus
    template.memory = vm.ram
    if has_balloonmem(vm.cluster):
        template.minmem = vm.minram
    template.disks = [{"size": size} for size in vm.info["disk.sizes"]]
    template.disk_type = vm.info["hvparams"]["disk_type"]
    template.nics = [{
        "mode": mode,
        "link": link
    } for mode, link in zip(vm.info["nic.modes"], vm.info["nic.links"])]
    template.nic_type = vm.info["hvparams"]["nic_type"]

    # Hypervisor parameters.
    template.kernel_path = vm.info["hvparams"]["kernel_path"]
    template.root_path = vm.info["hvparams"]["root_path"]
    template.serial_console = vm.info["hvparams"]["serial_console"]
    template.boot_order = vm.info["hvparams"]["boot_order"]
    template.cdrom_image_path = vm.info["hvparams"]["cdrom_image_path"]
    template.cdrom2_image_path = vm.info["hvparams"]["cdrom2_image_path"]

    template.save()

    return template
Example #4
0
def instance_to_template(vm, name):
    """
    Create, save, and return a VM template representing all of the information
    in the VM instance.

    The name is given to the template to distinguish it from other templates.
    """

    template = VirtualMachineTemplate()

    # Basic stuff first.
    template.template_name = name
    template.description = ""
    template.cluster = vm.cluster
    template.start = vm.info["admin_state"]
    template.disk_template = vm.info["disk_template"]
    template.os = vm.operating_system

    # Backend parameters.
    template.vcpus = vm.virtual_cpus
    template.memory = vm.ram
    if has_balloonmem(vm.cluster):
        template.minmem = vm.minram
    template.disks = [{"size": size} for size in vm.info["disk.sizes"]]
    template.disk_type = vm.info["hvparams"]["disk_type"]
    template.nics = [{"mode": mode, "link": link}
                     for mode, link in zip(vm.info["nic.modes"],
                                           vm.info["nic.links"])]
    template.nic_type = vm.info["hvparams"]["nic_type"]

    # Hypervisor parameters.
    template.kernel_path = vm.info["hvparams"]["kernel_path"]
    template.root_path = vm.info["hvparams"]["root_path"]
    template.serial_console = vm.info["hvparams"]["serial_console"]
    template.boot_order = vm.info["hvparams"]["boot_order"]
    template.cdrom_image_path = vm.info["hvparams"]["cdrom_image_path"]
    template.cdrom2_image_path = vm.info["hvparams"]["cdrom2_image_path"]

    template.save()

    return template
Example #5
0
def template_to_instance(template, hostname, owner):
    """
    Instantiate a VM template with a given hostname and owner.
    """

    cluster = template.cluster
    beparams = {
        "vcpus": template.vcpus,
    }

    hvparams = {}
    hv = template.hypervisor or cluster.info["default_hypervisor"]
    kvm = hv == 'kvm'
    pvm = hv == 'xen-pvm'
    hvm = hv == 'xen-hvm'
    kvm_or_hvm = kvm or hvm
    kvm_or_pvm = kvm or pvm

    if kvm_or_hvm:
        hvparams.update(boot_order=template.boot_order)
        hvparams.update(cdrom_image_path=template.cdrom_image_path)
        hvparams.update(nic_type=template.nic_type)
        hvparams.update(disk_type=template.disk_type)
    if kvm_or_pvm:
        hvparams.update(kernel_path=template.kernel_path)
        hvparams.update(root_path=template.root_path)
    if kvm:
        hvparams.update(cdrom2_image_path=template.cdrom2_image_path)
        hvparams.update(serial_console=template.serial_console)

    memory = template.memory
    if has_balloonmem(cluster):
        minram = template.minmem
        beparams['minmem'] = minram
        beparams['maxmem'] = memory
    else:
        beparams['memory'] = memory

    vcpus = template.vcpus
    disk_size = template.disks[0]["size"]

    kwargs = {
        "os": template.os,
        "hypervisor": hv,
        "ip_check": template.ip_check,
        "name_check": template.name_check,
        "beparams": beparams,
        "no_install": template.no_install,
        "start": template.start,
        "hvparams": hvparams,
    }

    # Using auto allocator
    if template.iallocator:
        default_iallocator = cluster.info['default_iallocator']
        kwargs.update(iallocator=default_iallocator)
    # Not using allocator, pass pnode
    else:
        kwargs.update(pnode=template.pnode)
        # Also pass in snode if it exists (drdb)
        if template.snode:
            kwargs.update(snode=template.snode)
        # secondary node isn't set but we're using drdb, so programming error
        # (this shouldn't happen if form validation is done correctly)
        elif template.disk_template == 'drdb':
            msg = 'Disk template set to drdb, but no secondary node set'
            raise RuntimeError(msg)

    job_id = cluster.rapi.CreateInstance('create', hostname,
                                         template.disk_template,
                                         template.disks, template.nics,
                                         **kwargs)
    vm = VirtualMachine()

    vm.cluster = cluster
    vm.hostname = hostname
    vm.ram = memory
    if has_balloonmem(cluster):
        vm.minram = minram
    vm.virtual_cpus = vcpus
    vm.disk_size = disk_size

    vm.owner = owner
    vm.ignore_cache = True

    # Do a dance to get the VM and the job referencing each other.
    vm.save()
    job = Job.objects.create(job_id=job_id, obj=vm, cluster=cluster)
    job.save()
    vm.last_job = job
    vm.save()

    # Grant admin permissions to the owner.
    owner.permissable.grant('admin', vm)

    return vm
Example #6
0
def template_to_instance(template, hostname, owner):
    """
    Instantiate a VM template with a given hostname and owner.
    """

    cluster = template.cluster
    beparams = {
        "vcpus": template.vcpus,
    }

    hvparams = {}
    hv = template.hypervisor or cluster.info["default_hypervisor"]
    kvm = hv == 'kvm'
    pvm = hv == 'xen-pvm'
    hvm = hv == 'xen-hvm'
    kvm_or_hvm = kvm or hvm
    kvm_or_pvm = kvm or pvm

    if kvm_or_hvm:
        hvparams.update(boot_order=template.boot_order)
        hvparams.update(cdrom_image_path=template.cdrom_image_path)
        hvparams.update(nic_type=template.nic_type)
        hvparams.update(disk_type=template.disk_type)
    if kvm_or_pvm:
        hvparams.update(kernel_path=template.kernel_path)
        hvparams.update(root_path=template.root_path)
    if kvm:
        hvparams.update(cdrom2_image_path=template.cdrom2_image_path)
        hvparams.update(serial_console=template.serial_console)

    memory = template.memory
    if has_balloonmem(cluster):
        minram = template.minmem
        beparams['minmem'] = minram
        beparams['maxmem'] = memory
    else:
        beparams['memory'] = memory

    vcpus = template.vcpus
    disk_size = template.disks[0]["size"]

    kwargs = {
        "os": template.os,
        "hypervisor": hv,
        "ip_check": template.ip_check,
        "name_check": template.name_check,
        "beparams": beparams,
        "no_install": template.no_install,
        "start": template.start,
        "hvparams": hvparams,
    }

    # Using auto allocator
    if template.iallocator:
        default_iallocator = cluster.info['default_iallocator']
        kwargs.update(iallocator=default_iallocator)
    # Not using allocator, pass pnode
    else:
        kwargs.update(pnode=template.pnode)
        # Also pass in snode if it exists (drdb)
        if template.snode:
            kwargs.update(snode=template.snode)
        # secondary node isn't set but we're using drdb, so programming error
        # (this shouldn't happen if form validation is done correctly)
        elif template.disk_template == 'drdb':
            msg = 'Disk template set to drdb, but no secondary node set'
            raise RuntimeError(msg)

    job_id = cluster.rapi.CreateInstance('create', hostname,
                                         template.disk_template,
                                         template.disks, template.nics,
                                         **kwargs)
    vm = VirtualMachine()

    vm.cluster = cluster
    vm.hostname = hostname
    vm.ram = memory
    if has_balloonmem(cluster):
        vm.minram = minram
    vm.virtual_cpus = vcpus
    vm.disk_size = disk_size

    vm.owner = owner
    vm.ignore_cache = True

    # Do a dance to get the VM and the job referencing each other.
    vm.save()
    job = Job.objects.create(job_id=job_id, obj=vm, cluster=cluster)
    job.save()
    vm.last_job = job
    vm.save()

    # Grant admin permissions to the owner.
    owner.permissable.grant('admin', vm)

    return vm
Example #7
0
def cluster_default_info(cluster, hypervisor=None):
    """
    Returns a dictionary containing the following
    default values set on a cluster:
        iallocator, hypervisors, vcpus, ram, nictype,
        nicmode, kernelpath, rootpath, serialconsole,
        bootorder, imagepath
    """
    # Create variables so that dictionary lookups are not so horrendous.
    info = cluster.info
    beparams = info['beparams']['default']
    hvs = info['enabled_hypervisors']

    if hypervisor is not None:
        if hypervisor not in hvs:
            raise RuntimeError("Was asked to deal with a cluster/HV mismatch")
        else:
            hv = hypervisor
    else:
        hv = info['default_hypervisor']

    hvparams = info['hvparams'][hv]
    if hv == 'kvm':
        c = constants.KVM_CHOICES
    elif hv == 'xen-hvm' or hv == 'xen-pvm':
        c = constants.HVM_CHOICES
        if hv == 'xen-pvm':
            # PVM does not have disk types or nic types, so these options get
            # taken from HVM. This does not affect forms as pvm ignores
            # the disk_type and nic_type fields.
            hvparams['disk_type'] = info['hvparams']['xen-hvm']['disk_type']
            hvparams['nic_type'] = info['hvparams']['xen-hvm']['nic_type']
    else:
        c = constants.NO_CHOICES

    disktypes = c['disk_type']
    nictypes = c['nic_type']
    bootdevices = c['boot_order']

    try:
        iallocator_info = info['default_iallocator']
    except:
        iallocator_info = None

    if 'nicparams' in info:
        nic_mode = info['nicparams']['default']['mode']
        nic_link = info['nicparams']['default']['link']
    else:
        nic_mode = None
        nic_link = None

    extraparams = {
        'boot_devices': bootdevices,
        'disk_types': disktypes,
        'hypervisor': hv,
        'hypervisors': zip(hvs, hvs),
        'iallocator': iallocator_info,
        'nic_types': nictypes,
        'nic_mode': nic_mode,
        'nic_link': nic_link,
        'vcpus': beparams['vcpus'],
    }

    if has_balloonmem(cluster):
        extraparams['memory'] = beparams['maxmem']
    else:
        extraparams['memory'] = beparams['memory']

    return dict(hvparams, **extraparams)
Example #8
0
def modify_confirm(request, cluster_slug, instance):
    vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance)

    hv = get_hypervisor(vm)
    if hv == 'kvm':
        hv_form = KvmModifyVirtualMachineForm
    elif hv == 'xen-pvm':
        hv_form = PvmModifyVirtualMachineForm
    elif hv == 'xen-hvm':
        hv_form = HvmModifyVirtualMachineForm
    else:
        hv_form = None
        # 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_confirm"
        raise RuntimeError(msg)

    user = request.user
    power = user.is_superuser or user.has_any_perms(vm, ['admin', 'power'])
    if not (user.is_superuser or user.has_any_perms(vm, ['admin', 'modify'])
            or user.has_perm('admin', cluster)):
        raise PermissionDenied(
            _('You do not have permissions to edit this virtual machine'))

    if request.method == "POST":
        if 'edit' in request.POST:
            return HttpResponseRedirect(
                reverse("instance-modify",
                        args=[cluster.slug, vm.hostname]))
        elif 'reboot' in request.POST or 'save' in request.POST:
            form = ModifyConfirmForm(request.POST)
            form.session = request.session
            form.owner = vm.owner
            form.vm = vm
            form.cluster = cluster

            if form.is_valid():
                beparams = {}
                data = form.cleaned_data
                rapi_dict = data['rapi_dict']
                nics = rapi_dict.pop('nics')
                beparams['vcpus'] = rapi_dict.pop('vcpus')
                if has_balloonmem(cluster):
                    beparams['maxmem'] = rapi_dict.pop('maxmem')
                    beparams['minmem'] = rapi_dict.pop('minmem')
                else:
                    beparams['memory'] = rapi_dict.pop('memory')
                os_name = rapi_dict.pop('os')
                notes = rapi_dict.pop('notes')
                job_id = cluster.rapi.ModifyInstance(
                    instance,
                    nics=nics,
                    os_name=os_name,
                    hvparams=rapi_dict,
                    beparams=beparams)
                # Create job and update message on virtual machine detail page
                job = Job.objects.create(job_id=job_id,
                                         obj=vm,
                                         cluster=cluster)
                VirtualMachine.objects \
                    .filter(id=vm.id).update(last_job=job, ignore_cache=True,
                                             note_text=notes)
                # log information about modifying this instance
                log_action('EDIT', user, vm)
                if 'reboot' in request.POST and vm.info['status'] == 'running':
                    if power:
                        # Reboot the vm
                        job = vm.reboot()
                        log_action('VM_REBOOT', user, vm, job)
                    else:
                        raise PermissionDenied(
                            _("Sorry, but you do not have permission "
                              "to reboot this machine."))

                # Redirect to instance-detail
                return HttpResponseRedirect(
                    reverse("instance-detail",
                            args=[cluster.slug, vm.hostname]))

        elif 'cancel' in request.POST:
            # Remove session variables.
            if 'edit_form' in request.session:
                del request.session['edit_form']
            # Redirect to instance-detail
            return HttpResponseRedirect(
                reverse("instance-detail", args=[cluster.slug, vm.hostname]))

    elif request.method == "GET":
        form = ModifyConfirmForm()

    session = request.session

    if 'edit_form' not in request.session:
        return HttpResponseBadRequest('Incorrect Session Data')

    data = session['edit_form']
    info = vm.info
    hvparams = info['hvparams']

    old_set = dict(
        vcpus=info['beparams']['vcpus'],
        os=info['os'],
        notes=vm.note_text
    )
    if has_balloonmem(cluster):
        old_set['maxmem'] = info['beparams']['maxmem']
        old_set['minmem'] = info['beparams']['minmem']
    else:
        old_set['memory'] = info['beparams']['memory']
    nic_count = len(info['nic.links'])
    for i in xrange(nic_count):
        old_set['nic_link_%s' % i] = info['nic.links'][i]
        old_set['nic_mac_%s' % i] = info['nic.macs'][i]

    # Add hvparams to the old_set
    old_set.update(hvparams)

    instance_diff = {}
    fields = hv_form(vm, data).fields
    for key in data.keys():
        if key in ['memory', 'maxmem', 'minmem']:
            diff = compare(render_storage(old_set[key]),
                           render_storage(data[key]))
        elif key == 'os':
            oses = os_prettify([old_set[key], data[key]])
            if len(oses) > 1:
                """
                XXX - Special case for a cluster with two different types of
                  optgroups (i.e. Image, Debootstrap).
                  The elements at 00 and 10:
                    The optgroups
                  The elements at 010 and 110:
                    Tuple containing the OS Name and OS value.
                  The elements at 0101 and 1101:
                    String containing the OS Name
                """
                oses[0][1][0] = list(oses[0][1][0])
                oses[1][1][0] = list(oses[1][1][0])
                oses[0][1][0][1] = '%s (%s)' % (oses[0][1][0][1], oses[0][0])
                oses[1][1][0][1] = '%s (%s)' % (oses[1][1][0][1], oses[1][0])
                oses = oses[0][1] + oses[1][1]
                diff = compare(oses[0][1], oses[1][1])
            else:
                oses = oses[0][1]
                diff = compare(oses[0][1], oses[1][1])
            # diff = compare(oses[0][1], oses[1][1])
        if key in ['nic_count', 'nic_count_original']:
            continue
        elif key not in old_set.keys():
            diff = ""
            instance_diff[fields[key].label] = _('Added')
        else:
            diff = compare(old_set[key], data[key])

        if diff != "":
            label = fields[key].label
            instance_diff[label] = diff

    # remove mac if it has not changed
    for i in xrange(nic_count):
        if fields['nic_mac_%s' % i].label not in instance_diff:
            del data['nic_mac_%s' % i]

    # Repopulate form with changed values
    form.fields['rapi_dict'] = CharField(widget=HiddenInput,
                                         initial=json.dumps(data))

    return render_to_response(
        'ganeti/virtual_machine/edit_confirm.html',
        {
            'cluster': cluster,
            'form': form,
            'instance': vm,
            'instance_diff': instance_diff,
            'power': power,
        },
        context_instance=RequestContext(request),
    )
Example #9
0
def modify_confirm(request, cluster_slug, instance):
    vm, cluster = get_vm_and_cluster_or_404(cluster_slug, instance)

    hv = get_hypervisor(vm)
    if hv == 'kvm':
        hv_form = KvmModifyVirtualMachineForm
    elif hv == 'xen-pvm':
        hv_form = PvmModifyVirtualMachineForm
    elif hv == 'xen-hvm':
        hv_form = HvmModifyVirtualMachineForm
    else:
        hv_form = None
        # 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_confirm"
        raise RuntimeError(msg)

    user = request.user
    power = user.is_superuser or user.has_any_perms(vm, ['admin', 'power'])
    if not (user.is_superuser or user.has_any_perms(vm, ['admin', 'modify'])
            or user.has_perm('admin', cluster)):
        raise PermissionDenied(
            _('You do not have permissions to edit this virtual machine'))

    if request.method == "POST":
        if 'edit' in request.POST:
            return HttpResponseRedirect(
                reverse("instance-modify", args=[cluster.slug, vm.hostname]))
        elif 'reboot' in request.POST or 'save' in request.POST:
            form = ModifyConfirmForm(request.POST)
            form.session = request.session
            form.owner = vm.owner
            form.vm = vm
            form.cluster = cluster

            if form.is_valid():
                beparams = {}
                data = form.cleaned_data
                rapi_dict = data['rapi_dict']
                nics = rapi_dict.pop('nics')
                beparams['vcpus'] = rapi_dict.pop('vcpus')
                if has_balloonmem(cluster):
                    beparams['maxmem'] = rapi_dict.pop('maxmem')
                    beparams['minmem'] = rapi_dict.pop('minmem')
                else:
                    beparams['memory'] = rapi_dict.pop('memory')
                os_name = rapi_dict.pop('os')
                notes = rapi_dict.pop('notes')
                job_id = cluster.rapi.ModifyInstance(instance,
                                                     nics=nics,
                                                     os_name=os_name,
                                                     hvparams=rapi_dict,
                                                     beparams=beparams)
                # Create job and update message on virtual machine detail page
                job = Job.objects.create(job_id=job_id,
                                         obj=vm,
                                         cluster=cluster)
                VirtualMachine.objects \
                    .filter(id=vm.id).update(last_job=job, ignore_cache=True,
                                             note_text=notes)
                # log information about modifying this instance
                log_action('EDIT', user, vm)
                if 'reboot' in request.POST and vm.info['status'] == 'running':
                    if power:
                        # Reboot the vm
                        job = vm.reboot()
                        log_action('VM_REBOOT', user, vm, job)
                    else:
                        raise PermissionDenied(
                            _("Sorry, but you do not have permission "
                              "to reboot this machine."))

                # Redirect to instance-detail
                return HttpResponseRedirect(
                    reverse("instance-detail",
                            args=[cluster.slug, vm.hostname]))

        elif 'cancel' in request.POST:
            # Remove session variables.
            if 'edit_form' in request.session:
                del request.session['edit_form']
            # Redirect to instance-detail
            return HttpResponseRedirect(
                reverse("instance-detail", args=[cluster.slug, vm.hostname]))

    elif request.method == "GET":
        form = ModifyConfirmForm()

    session = request.session

    if 'edit_form' not in request.session:
        return HttpResponseBadRequest('Incorrect Session Data')

    data = session['edit_form']
    info = vm.info
    hvparams = info['hvparams']

    old_set = dict(vcpus=info['beparams']['vcpus'],
                   os=info['os'],
                   notes=vm.note_text)
    if has_balloonmem(cluster):
        old_set['maxmem'] = info['beparams']['maxmem']
        old_set['minmem'] = info['beparams']['minmem']
    else:
        old_set['memory'] = info['beparams']['memory']
    nic_count = len(info['nic.links'])
    for i in xrange(nic_count):
        old_set['nic_link_%s' % i] = info['nic.links'][i]
        old_set['nic_mac_%s' % i] = info['nic.macs'][i]

    # Add hvparams to the old_set
    old_set.update(hvparams)

    instance_diff = {}
    fields = hv_form(vm, data).fields
    for key in data.keys():
        if key in ['memory', 'maxmem', 'minmem']:
            diff = compare(render_storage(old_set[key]),
                           render_storage(data[key]))
        elif key == 'os':
            oses = os_prettify([old_set[key], data[key]])
            if len(oses) > 1:
                """
                XXX - Special case for a cluster with two different types of
                  optgroups (i.e. Image, Debootstrap).
                  The elements at 00 and 10:
                    The optgroups
                  The elements at 010 and 110:
                    Tuple containing the OS Name and OS value.
                  The elements at 0101 and 1101:
                    String containing the OS Name
                """
                oses[0][1][0] = list(oses[0][1][0])
                oses[1][1][0] = list(oses[1][1][0])
                oses[0][1][0][1] = '%s (%s)' % (oses[0][1][0][1], oses[0][0])
                oses[1][1][0][1] = '%s (%s)' % (oses[1][1][0][1], oses[1][0])
                oses = oses[0][1] + oses[1][1]
                diff = compare(oses[0][1], oses[1][1])
            else:
                oses = oses[0][1]
                diff = compare(oses[0][1], oses[1][1])
            # diff = compare(oses[0][1], oses[1][1])
        if key in ['nic_count', 'nic_count_original']:
            continue
        elif key not in old_set.keys():
            diff = ""
            instance_diff[fields[key].label] = _('Added')
        else:
            diff = compare(old_set[key], data[key])

        if diff != "":
            label = fields[key].label
            instance_diff[label] = diff

    # remove mac if it has not changed
    for i in xrange(nic_count):
        if fields['nic_mac_%s' % i].label not in instance_diff:
            del data['nic_mac_%s' % i]

    # Repopulate form with changed values
    form.fields['rapi_dict'] = CharField(widget=HiddenInput,
                                         initial=json.dumps(data))

    return render_to_response(
        'ganeti/virtual_machine/edit_confirm.html',
        {
            'cluster': cluster,
            'form': form,
            'instance': vm,
            'instance_diff': instance_diff,
            'power': power,
        },
        context_instance=RequestContext(request),
    )