Hi all, I wanted the floppy support as well as others want it in the forums, so I decided to get it to work again.
I adapted the patches from this forum post http://forum.proxmox.com/threads/10910-Floppy-patch to current 3.4er branches of the corresponding packages. I fixed some additional minor bugs corresponding to the previous patches, yet I couldn't get the boot order right. Manual setting the boot order works, yet the bootindex stuff, which is generated by the code does not work for floppy (bootindex is not a valid keyword). Nevertheless, I attached the patches (one patch per git-repository, no format patch) and maybe we can the boot-order stuff working together. Maybe Romain_Orange will - as well as I - agree to the contributor agreement. Best regards from Saarbrücken, Andreas
diff --git a/www/manager/Makefile b/www/manager/Makefile index 6876c74..35db90f 100644 --- a/www/manager/Makefile +++ b/www/manager/Makefile @@ -62,6 +62,7 @@ JSSRC= \ form/BackupModeSelector.js \ form/ScsiHwSelector.js \ form/FirewallPolicySelector.js \ + form/FloppySelector.js \ dc/Tasks.js \ dc/Log.js \ panel/StatusPanel.js \ @@ -139,6 +140,8 @@ JSSRC= \ qemu/SnapshotTree.js \ qemu/Config.js \ qemu/CreateWizard.js \ + qemu/FloppyInputPanel.js \ + qemu/FloppyEdit.js \ openvz/StatusView.js \ openvz/Summary.js \ openvz/RessourceEdit.js \ diff --git a/www/manager/Utils.js b/www/manager/Utils.js index c293b06..3a5bb9c 100644 --- a/www/manager/Utils.js +++ b/www/manager/Utils.js @@ -715,6 +715,7 @@ Ext.define('PVE.Utils', { statics: { backupFileText: gettext('VZDump backup file'), vztmplText: gettext('OpenVZ template'), isoImageText: gettext('ISO image'), + flpText: gettext('Floppy image'), containersText: gettext('OpenVZ Container'), format_expire: function(date) { @@ -777,6 +778,8 @@ Ext.define('PVE.Utils', { statics: { cta.push(PVE.Utils.vztmplText); } else if (ct === 'iso') { cta.push(PVE.Utils.isoImageText); + } else if (ct === 'flp') { + cta.push(PVE.Utils.flpText); } else if (ct === 'rootdir') { cta.push(PVE.Utils.containersText); } diff --git a/www/manager/form/ContentTypeSelector.js b/www/manager/form/ContentTypeSelector.js index 0c74524..965fb9a 100644 --- a/www/manager/form/ContentTypeSelector.js +++ b/www/manager/form/ContentTypeSelector.js @@ -10,7 +10,7 @@ Ext.define('PVE.form.ContentTypeSelector', { me.data = []; if (me.cts === undefined) { - me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir']; + me.cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir','flp']; } Ext.Array.each(me.cts, function(ct) { diff --git a/www/manager/form/FloppySelector.js b/www/manager/form/FloppySelector.js new file mode 100644 index 0000000..1bf2eef --- /dev/null +++ b/www/manager/form/FloppySelector.js @@ -0,0 +1,89 @@ +Ext.define('PVE.form.FloppySelector', { + extend: 'Ext.form.FieldContainer', + alias: ['widget.PVE.form.FloppySelector'], + + statics: { + maxIds: { + floppy: 2 + } + }, + + vmconfig: {}, // used to check for existing devices + + setVMConfig: function(vmconfig, autoSelect) { + var me = this; + + me.vmconfig = Ext.apply({}, vmconfig); + if (autoSelect) { + var clist = ['floppy']; + + Ext.Array.each(clist, function(controller) { + var confid, i; + + me.down('field[name=controller]').setValue(controller); + for (i = 0; i <= PVE.form.ControllerSelector.maxIds[controller]; i++) { + confid = controller + i.toString(); + if (!Ext.isDefined(me.vmconfig[confid])) { + me.down('field[name=deviceid]').setValue(i); + return false; // break + } + } + }); + } + me.down('field[name=deviceid]').validate(); + }, + + initComponent: function() { + var me = this; + + Ext.apply(me, { + fieldLabel: 'Bus/Device', + layout: 'hbox', + height: 22, // hack: set to same height as other fields + defaults: { + flex: 1, + hideLabel: true + }, + items: [ + { + xtype: 'PVE.form.BusTypeSelector', + name: 'controller', + value: 'floppy', + allowBlank: false, + listeners: { + change: function(t, value) { + if (!me.rendered || !value) { + return; + } + var field = me.down('field[name=deviceid]'); + field.setMaxValue(PVE.form.ControllerSelector.maxIds[value]); + field.validate(); + } + } + }, + { + xtype: 'numberfield', + name: 'deviceid', + minValue: 0, + maxValue: PVE.form.ControllerSelector.maxIds.floppy, + value: '0', + validator: function(value) { + /*jslint confusion: true */ + if (!me.rendered) { + return; + } + var field = me.down('field[name=controller]'); + var controller = field.getValue(); + var confid = controller + value; + if (Ext.isDefined(me.vmconfig[confid])) { + return "This device is already in use."; + } + return true; + } + } + ] + }); + + me.callParent(); + } +}); diff --git a/www/manager/qemu/BootOrderEdit.js b/www/manager/qemu/BootOrderEdit.js index 9601313..1695025 100644 --- a/www/manager/qemu/BootOrderEdit.js +++ b/www/manager/qemu/BootOrderEdit.js @@ -73,9 +73,9 @@ Ext.define('PVE.qemu.BootOrderPanel', { if (sel1 !== 'n' && (sel2 !== 'n')) { list.push(['n', gettext('Network')]); } - //if (sel1 !== 'a' && (sel2 !== 'a')) { - // list.push(['a', 'Floppy']); - //} + if (sel1 !== 'a' && (sel2 !== 'a')) { + list.push(['a', 'Floppy']); + } if (includeNone) { list.push(['', PVE.Utils.noneText]); diff --git a/www/manager/qemu/FloppyEdit.js b/www/manager/qemu/FloppyEdit.js new file mode 100644 index 0000000..1ffb039 --- /dev/null +++ b/www/manager/qemu/FloppyEdit.js @@ -0,0 +1,42 @@ +Ext.define('PVE.qemu.FloppyEdit', { + extend: 'PVE.window.Edit', + + initComponent : function() { + var me = this; + + var nodename = me.pveSelNode.data.node; + if (!nodename) { + throw "no node name specified"; + } + + me.create = me.confid ? false : true; + + var ipanel = Ext.create('PVE.qemu.FloppyInputPanel', { + confid: me.confid, + nodename: nodename + }); + + Ext.applyIf(me, { + subject: 'Floppy Drive', + items: [ ipanel ] + }); + + me.callParent(); + + me.load({ + success: function(response, options) { + ipanel.setVMConfig(response.result.data); + if (me.confid) { + var value = response.result.data[me.confid]; + var drive = PVE.Parser.parseQemuDrive(me.confid, value); + if (!drive) { + Ext.Msg.alert('Error', 'Unable to parse drive options'); + me.close(); + return; + } + ipanel.setDrive(drive); + } + } + }); + } +}); diff --git a/www/manager/qemu/FloppyInputPanel.js b/www/manager/qemu/FloppyInputPanel.js new file mode 100644 index 0000000..184764f --- /dev/null +++ b/www/manager/qemu/FloppyInputPanel.js @@ -0,0 +1,136 @@ +Ext.define('PVE.qemu.FloppyInputPanel', { + extend: 'PVE.panel.InputPanel', + alias: 'widget.PVE.qemu.FloppyInputPanel', + + insideWizard: false, + + onGetValues: function(values) { + var me = this; + + var confid = me.confid || (values.controller + values.deviceid); + + me.drive.media = 'disk'; + if (values.mediaType === 'flp') { + me.drive.file = values.cdimage; + }else { + me.drive.file = 'none'; + } + + var params = {}; + + params[confid] = PVE.Parser.printQemuDrive(me.drive); + + return params; + }, + + setVMConfig: function(vmconfig) { + var me = this; + + if (me.bussel) { + me.bussel.setVMConfig(vmconfig, true); + } + }, + + setDrive: function(drive) { + var me = this; + + var values = {}; + if (drive.file === 'flp') { + values.mediaType = 'flp'; + } else if (drive.file === 'none') { + values.mediaType = 'none'; + } else { + values.mediaType = 'flp'; + var match = drive.file.match(/^([^:]+):/); + if (match) { + values.cdstorage = match[1]; + values.cdimage = drive.file; + } + } + + me.drive = drive; + + me.setValues(values); + }, + + setNodename: function(nodename) { + var me = this; + + me.cdstoragesel.setNodename(nodename); + me.cdfilesel.setStorage(undefined, nodename); + }, + + initComponent : function() { + var me = this; + + me.drive = {}; + + var items = []; + + if (!me.confid) { + me.bussel = Ext.createWidget('PVE.form.FloppySelector'); + items.push(me.bussel); + } + + items.push({ + xtype: 'radiofield', + name: 'mediaType', + inputValue: 'flp', + boxLabel: 'Use Floppy flp image file', + checked: true, + listeners: { + change: function(f, value) { + if (!me.rendered) { + return; + } + me.down('field[name=cdstorage]').setDisabled(!value); + me.down('field[name=cdimage]').setDisabled(!value); + me.down('field[name=cdimage]').validate(); + } + } + }); + + me.cdfilesel = Ext.create('PVE.form.FileSelector', { + name: 'cdimage', + nodename: me.nodename, + storageContent: 'flp', + fieldLabel: 'Flp Image', + labelAlign: 'right', + allowBlank: false + }); + + me.cdstoragesel = Ext.create('PVE.form.StorageSelector', { + name: 'cdstorage', + nodename: me.nodename, + fieldLabel: gettext('Storage'), + labelAlign: 'right', + storageContent: 'flp', + allowBlank: false, + autoSelect: me.insideWizard, + listeners: { + change: function(f, value) { + me.cdfilesel.setStorage(value); + } + } + }); + + items.push(me.cdstoragesel); + items.push(me.cdfilesel); + + items.push({ + xtype: 'radiofield', + name: 'mediaType', + inputValue: 'none', + boxLabel: 'Do not use any media' + }); + + if (me.insideWizard) { + me.column1 = items; + } else { + me.items = items; + } + + me.callParent(); + } +}); + diff --git a/www/manager/qemu/HardwareView.js b/www/manager/qemu/HardwareView.js index 43f6c1e..40b320e 100644 --- a/www/manager/qemu/HardwareView.js +++ b/www/manager/qemu/HardwareView.js @@ -151,6 +151,16 @@ Ext.define('PVE.qemu.HardwareView', { cdheader: gettext('CD/DVD Drive') + ' (' + confid +')' }; } + for (i = 0; i < 2; i++) { + confid = "floppy" + i; + rows[confid] = { + group: 1, + tdCls: 'pve-itype-icon-storage', + editor: 'PVE.qemu.FloppyEdit', + header: gettext('Floppy Drive') + ' (' + confid +')', + cdheader: gettext('Floppy Drive') + ' (' + confid +')' + }; + } for (i = 0; i < 16; i++) { confid = "virtio" + i; rows[confid] = { @@ -434,6 +444,19 @@ Ext.define('PVE.qemu.HardwareView', { win.show(); } }, + { + text: gettext('Floppy Drive'), + iconCls: 'pve-itype-icon-storage', + //disabled: !caps.vms['VM.Config.Floppy'], + handler: function() { + var win = Ext.create('PVE.qemu.FloppyEdit', { + url: '/api2/extjs/' + baseurl, + pveSelNode: me.pveSelNode + }); + win.on('destroy', reload); + win.show(); + } + }, { text: gettext('Network Device'), iconCls: 'pve-itype-icon-network', diff --git a/www/manager/storage/ContentView.js b/www/manager/storage/ContentView.js index fcbb0ac..16aad03 100644 --- a/www/manager/storage/ContentView.js +++ b/www/manager/storage/ContentView.js @@ -184,7 +184,7 @@ Ext.define('PVE.storage.Upload', { items: [ { xtype: 'pveContentTypeSelector', - cts: ['iso', 'backup', 'vztmpl'], + cts: ['iso', 'backup', 'vztmpl', 'flp'], fieldLabel: gettext('Content'), name: 'content', value: 'iso'
diff --git a/PVE/API2/Storage/Config.pm b/PVE/API2/Storage/Config.pm index 27b3a55..bcb2edd 100755 --- a/PVE/API2/Storage/Config.pm +++ b/PVE/API2/Storage/Config.pm @@ -17,7 +17,7 @@ use PVE::RESTHandler; use base qw(PVE::RESTHandler); -my @ctypes = qw(images vztmpl iso backup); +my @ctypes = qw(images vztmpl iso backup flp); my $storage_type_enum = PVE::Storage::Plugin->lookup_types(); diff --git a/PVE/API2/Storage/Content.pm b/PVE/API2/Storage/Content.pm index 605e455..dd15208 100644 --- a/PVE/API2/Storage/Content.pm +++ b/PVE/API2/Storage/Content.pm @@ -77,6 +77,8 @@ __PACKAGE__->register_method ({ $data = PVE::Storage::vdisk_list ($cfg, $storeid, $param->{vmid}); } elsif ($ct eq 'iso') { $data = PVE::Storage::template_list ($cfg, $storeid, 'iso'); + } elsif ($ct eq 'flp') { + $data = PVE::Storage::template_list ($cfg, $storeid, 'flp'); } elsif ($ct eq 'vztmpl') { $data = PVE::Storage::template_list ($cfg, $storeid, 'vztmpl'); } elsif ($ct eq 'backup') { diff --git a/PVE/API2/Storage/Status.pm b/PVE/API2/Storage/Status.pm index d9326b7..0051345 100644 --- a/PVE/API2/Storage/Status.pm +++ b/PVE/API2/Storage/Status.pm @@ -350,6 +350,11 @@ __PACKAGE__->register_method ({ raise_param_exc({ filename => "missing '.iso' extension" }); } $path = PVE::Storage::get_iso_dir($cfg, $param->{storage}); + } elsif ($content eq 'flp') { + if ($filename !~ m![^/]+\.[Ff][Ll][Pp]$!) { + raise_param_exc({ filename => "missing '.flp' extension" }); + } + $path = PVE::Storage::get_flp_dir($cfg, $param->{storage}); } elsif ($content eq 'vztmpl') { if ($filename !~ m![^/]+\.tar\.gz$!) { raise_param_exc({ filename => "missing '.tar.gz' extension" }); diff --git a/PVE/Storage.pm b/PVE/Storage.pm index e46bc77..afe025f 100755 --- a/PVE/Storage.pm +++ b/PVE/Storage.pm @@ -251,6 +251,15 @@ sub get_iso_dir { return $plugin->get_subdir($scfg, 'iso'); } +sub get_flp_dir { + my ($cfg, $storeid) = @_; + + my $scfg = storage_config($cfg, $storeid); + my $plugin = PVE::Storage::Plugin->lookup($scfg->{type}); + + return $plugin->get_subdir($scfg, 'flp'); +} + sub get_vztmpl_dir { my ($cfg, $storeid) = @_; @@ -348,6 +357,7 @@ sub path_to_volume_id { my $tmpldir = $plugin->get_subdir($scfg, 'vztmpl'); my $backupdir = $plugin->get_subdir($scfg, 'backup'); my $privatedir = $plugin->get_subdir($scfg, 'rootdir'); + my $flpdir = $plugin->get_subdir($scfg, 'flp'); if ($path =~ m!^$imagedir/(\d+)/([^/\s]+)$!) { my $vmid = $1; @@ -364,6 +374,9 @@ sub path_to_volume_id { } elsif ($path =~ m!^$isodir/([^/]+\.[Ii][Ss][Oo])$!) { my $name = $1; return ('iso', "$sid:iso/$name"); + } elsif ($path =~ m!^$flpdir/([^/]+\.[Ff][Ll][Pp])$!) { + my $name = $1; + return ('flp', "$sid:flp/$name"); } elsif ($path =~ m!^$tmpldir/([^/]+\.tar\.gz)$!) { my $name = $1; return ('vztmpl', "$sid:vztmpl/$name"); @@ -611,7 +624,7 @@ sub template_list { my ($cfg, $storeid, $tt) = @_; die "unknown template type '$tt'\n" - if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup'); + if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup' || $tt eq 'flp' ); my $ids = $cfg->{ids}; @@ -632,6 +645,7 @@ sub template_list { next if $tt eq 'iso' && !$scfg->{content}->{iso}; next if $tt eq 'vztmpl' && !$scfg->{content}->{vztmpl}; next if $tt eq 'backup' && !$scfg->{content}->{backup}; + next if $tt eq 'flp' && !$scfg->{content}->{flp}; activate_storage($cfg, $sid); @@ -649,6 +663,11 @@ sub template_list { $info = { volid => "$sid:iso/$1", format => 'iso' }; + } elsif ($tt eq 'flp') { + next if $fn !~ m!/([^/]+\.[Ff][Ll][Pp])$!; + + $info = { volid => "$sid:flp/$1", format => 'flp' }; + } elsif ($tt eq 'vztmpl') { next if $fn !~ m!/([^/]+\.tar\.gz)$!; diff --git a/PVE/Storage/DirPlugin.pm b/PVE/Storage/DirPlugin.pm index 41842f2..e74a987 100644 --- a/PVE/Storage/DirPlugin.pm +++ b/PVE/Storage/DirPlugin.pm @@ -16,7 +16,7 @@ sub type { sub plugindata { return { - content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, none => 1 }, + content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, flp => 1, none => 1 }, { images => 1, rootdir => 1 }], format => [ { raw => 1, qcow2 => 1, vmdk => 1 } , 'raw' ], }; diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm index 3eb99f2..51d747d 100644 --- a/PVE/Storage/Plugin.pm +++ b/PVE/Storage/Plugin.pm @@ -364,6 +364,8 @@ sub parse_volname { return ('images', $name, $vmid, undef, undef, $isBase); } elsif ($volname =~ m!^iso/([^/]+\.[Ii][Ss][Oo])$!) { return ('iso', $1); + } elsif ($volname =~ m!^flp/([^/]+\.[Ff][Ll][Pp])$!) { + return ('flp', $1); } elsif ($volname =~ m!^vztmpl/([^/]+\.tar\.gz)$!) { return ('vztmpl', $1); } elsif ($volname =~ m!^rootdir/(\d+)$!) { @@ -382,6 +384,7 @@ sub parse_volname { my $vtype_subdirs = { images => 'images', rootdir => 'private', + flp => 'flp', iso => 'template/iso', vztmpl => 'template/cache', backup => 'dump',
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 2720540..dd4eb7e 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -489,6 +489,7 @@ my $MAX_UNUSED_DISKS = 8; my $MAX_HOSTPCI_DEVICES = 4; my $MAX_SERIAL_PORTS = 4; my $MAX_PARALLEL_PORTS = 3; +my $MAX_FLOPPY_DEVICES = 2; my $MAX_NUMA = 8; my $MAX_MEM = 4194304; my $STATICMEM = 1024; @@ -643,6 +644,18 @@ Experimental: user reported problems with this option. EODESCR }; +my $floppydesc= { + optional => 1, + type => 'string', format => 'pve-qm-drive', + typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback|unsafe] [,format=f] [,backup=yes|no] [,rerror=ignore|report|stop] [,werror=enospc|ignore|report|stop] [,aio=native|threads]', + description => <<EODESCR, + + Note : OB floppy plugin + +EODESCR +}; +PVE::JSONSchema::register_standard_option("pve-qm-floppy", $floppydesc); + for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) { $confdesc->{"parallel$i"} = $paralleldesc; } @@ -678,6 +691,10 @@ for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) { for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) { $confdesc->{"usb$i"} = $usbdesc; } +for (my $i = 0; $i < $MAX_FLOPPY_DEVICES; $i++) { + $drivename_hash->{"floppy$i"} = 1; + $confdesc->{"floppy$i"} = $floppydesc; +} my $unuseddesc = { optional => 1, @@ -729,10 +746,13 @@ my $kernel_has_vhost_net = -c '/dev/vhost-net'; sub disknames { # order is important - used to autoselect boot disk - return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))), + return ( + (map { "floppy$_" } (0 .. ($MAX_FLOPPY_DEVICES - 1))), + (map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))), (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))), (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))), - (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1)))); + (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))) + ); } sub valid_drivename { @@ -1197,6 +1217,7 @@ sub print_drivedevice_full { } elsif ($drive->{interface} eq 'usb') { die "implement me"; # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 + } elsif ($drive->{interface} eq 'floppy') { } else { die "unsupported interface type"; } @@ -1256,6 +1277,10 @@ sub print_drive_full { my $pathinfo = $path ? "file=$path," : ''; + if($drive->{interface} eq 'floppy'){ + return "${pathinfo}index=$drive->{index},if=floppy"; + } + return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts"; } @@ -3099,6 +3124,10 @@ sub config_to_command { $drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds); $bootindex_hash->{c} += 1; } + if ($bootindex_hash->{a}) { + $drive->{bootindex} = $bootindex_hash->{a} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds); + $bootindex_hash->{a} += 1; + } } if ($drive->{interface} eq 'scsi') { @@ -3119,7 +3148,9 @@ sub config_to_command { my $drive_cmd = print_drive_full($storecfg, $vmid, $drive); push @$devices, '-drive',$drive_cmd; - push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges); + if($drive->{interface} ne 'floppy'){ + push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges); + } }); for (my $i = 0; $i < $MAX_NETS; $i++) {
_______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel