Commit bec1da7a authored by Dietmar Maurer's avatar Dietmar Maurer

support more than 'local' storage for openvz.

It is now possible to use NFS or other directory type storages.
parent 6ea2c67c
...@@ -87,16 +87,16 @@ __PACKAGE__->register_method({ ...@@ -87,16 +87,16 @@ __PACKAGE__->register_method({
}}); }});
my $restore_openvz = sub { my $restore_openvz = sub {
my ($archive, $vmid, $force) = @_; my ($private, $archive, $vmid, $force) = @_;
my $vzconf = PVE::OpenVZ::read_global_vz_config (); my $vzconf = PVE::OpenVZ::read_global_vz_config ();
my $conffile = PVE::OpenVZ::config_file($vmid); my $conffile = PVE::OpenVZ::config_file($vmid);
my $cfgdir = dirname($conffile); my $cfgdir = dirname($conffile);
my $private = $vzconf->{privatedir};
$private =~ s/\$VEID/$vmid/;
my $root = $vzconf->{rootdir}; my $root = $vzconf->{rootdir};
$root =~ s/\$VEID/$vmid/; $root =~ s/\$VEID/$vmid/;
my $default_private = $vzconf->{privatedir};
$default_private =~ s/\$VEID/$vmid/;
print "you choose to force overwriting VPS config file, private and root directories.\n" if $force; print "you choose to force overwriting VPS config file, private and root directories.\n" if $force;
...@@ -112,8 +112,15 @@ my $restore_openvz = sub { ...@@ -112,8 +112,15 @@ my $restore_openvz = sub {
my $conf; my $conf;
eval { eval {
rmtree $private if -d $private; if ($force && -f $conffile) {
rmtree $root if -d $root; my $conf = PVE::OpenVZ::load_config($vmid);
my $oldprivate = $conf->{ve_private} ? $conf->{ve_private}->{value} : $default_private;
rmtree $oldprivate if -d $oldprivate;
my $oldroot = $conf->{ve_root} ? $conf->{ve_root}->{value} : $root;
rmtree $oldroot if -d $oldroot;
};
mkpath $private || die "unable to create private dir '$private'"; mkpath $private || die "unable to create private dir '$private'";
mkpath $root || die "unable to create private dir '$private'"; mkpath $root || die "unable to create private dir '$private'";
...@@ -191,6 +198,11 @@ __PACKAGE__->register_method({ ...@@ -191,6 +198,11 @@ __PACKAGE__->register_method({
type => 'string', type => 'string',
description => "Sets root password inside container.", description => "Sets root password inside container.",
}, },
storage => get_standard_option('pve-storage-id', {
description => "Target storage.",
default => 'local',
optional => 1,
}),
force => { force => {
optional => 1, optional => 1,
type => 'boolean', type => 'boolean',
...@@ -219,7 +231,18 @@ __PACKAGE__->register_method({ ...@@ -219,7 +231,18 @@ __PACKAGE__->register_method({
my $password = extract_param($param, 'password'); my $password = extract_param($param, 'password');
my $stcfg = cfs_read_file("storage.cfg"); my $storage = extract_param($param, 'storage') || 'local';
my $storage_cfg = cfs_read_file("storage.cfg");
my $scfg = PVE::Storage::storage_check_node($storage_cfg, $storage, $node);
raise_param_exc({ storage => "storage '$storage' does not support openvz root directories"})
if !$scfg->{content}->{rootdir};
my $private = PVE::Storage::get_private_dir($storage_cfg, $storage, $vmid);
PVE::Storage::activate_storage($storage_cfg, $storage);
my $conf = PVE::OpenVZ::parse_ovz_config("/tmp/openvz/$vmid.conf", $pve_base_ovz_config); my $conf = PVE::OpenVZ::parse_ovz_config("/tmp/openvz/$vmid.conf", $pve_base_ovz_config);
...@@ -245,7 +268,7 @@ __PACKAGE__->register_method({ ...@@ -245,7 +268,7 @@ __PACKAGE__->register_method({
$archive = '-'; $archive = '-';
} else { } else {
if (PVE::Storage::parse_volume_id($ostemplate, 1)) { if (PVE::Storage::parse_volume_id($ostemplate, 1)) {
$archive = PVE::Storage::path($stcfg, $ostemplate); $archive = PVE::Storage::path($storage_cfg, $ostemplate);
} else { } else {
raise_param_exc({ archive => "Only root can pass arbitrary paths." }) raise_param_exc({ archive => "Only root can pass arbitrary paths." })
if $user ne 'root@pam'; if $user ne 'root@pam';
...@@ -275,6 +298,7 @@ __PACKAGE__->register_method({ ...@@ -275,6 +298,7 @@ __PACKAGE__->register_method({
$conf->{ostemplate}->{value} = $archive; $conf->{ostemplate}->{value} = $archive;
$conf->{ostemplate}->{value} =~ s|^.*/||; $conf->{ostemplate}->{value} =~ s|^.*/||;
$conf->{ostemplate}->{value} =~ s/\.tar\.(gz|bz2)$//; $conf->{ostemplate}->{value} =~ s/\.tar\.(gz|bz2)$//;
$conf->{ve_private}->{value} = $private;
} }
my $rawconf = PVE::OpenVZ::generate_raw_config($pve_base_ovz_config, $conf); my $rawconf = PVE::OpenVZ::generate_raw_config($pve_base_ovz_config, $conf);
...@@ -282,14 +306,14 @@ __PACKAGE__->register_method({ ...@@ -282,14 +306,14 @@ __PACKAGE__->register_method({
PVE::Cluster::check_cfs_quorum(); PVE::Cluster::check_cfs_quorum();
my $realcmd = sub { my $realcmd = sub {
&$restore_openvz($archive, $vmid, $param->{force}); &$restore_openvz($private, $archive, $vmid, $param->{force});
PVE::Tools::file_set_contents($basecfg_fn, $rawconf) PVE::Tools::file_set_contents($basecfg_fn, $rawconf)
if !$param->{restore}; if !$param->{restore};
# hack: vzctl '--userpasswd' starts the CT, but we want # hack: vzctl '--userpasswd' starts the CT, but we want
# to avoid that for create # to avoid that for create
PVE::OpenVZ::set_rootpasswd($vmid, $password) if defined($password); PVE::OpenVZ::set_rootpasswd($private, $password) if defined($password);
}; };
return $rpcenv->fork_worker($param->{restore} ? 'vzrestore' : 'vzcreate', return $rpcenv->fork_worker($param->{restore} ? 'vzrestore' : 'vzcreate',
......
...@@ -197,7 +197,7 @@ sub vmstatus { ...@@ -197,7 +197,7 @@ sub vmstatus {
if (my $fh = IO::File->new ("/proc/mounts", "r")) { if (my $fh = IO::File->new ("/proc/mounts", "r")) {
while (defined (my $line = <$fh>)) { while (defined (my $line = <$fh>)) {
if ($line =~ m|^/var/lib/vz/private/(\d+)\s+/var/lib/vz/root/|) { if ($line =~ m|/private/(\d+)\s+/var/lib/vz/root/\d+\s|) {
$list->{$1}->{status} = 'mounted' if defined($list->{$1}); $list->{$1}->{status} = 'mounted' if defined($list->{$1});
} }
} }
...@@ -219,7 +219,7 @@ sub vmstatus { ...@@ -219,7 +219,7 @@ sub vmstatus {
if (my $fh = IO::File->new ("/proc/vz/vzquota", "r")) { if (my $fh = IO::File->new ("/proc/vz/vzquota", "r")) {
while (defined (my $line = <$fh>)) { while (defined (my $line = <$fh>)) {
if ($line =~ m|^(\d+):\s+/var/lib/vz/private/\d+$|) { if ($line =~ m|^(\d+):\s+\S+/private/\d+$|) {
my $vmid = $1; my $vmid = $1;
my $d = $list->{$vmid}; my $d = $list->{$vmid};
if ($d && defined($d->{status})) { if ($d && defined($d->{status})) {
...@@ -1173,16 +1173,13 @@ sub replacepw { ...@@ -1173,16 +1173,13 @@ sub replacepw {
} }
sub set_rootpasswd { sub set_rootpasswd {
my ($vmid, $opt_rootpasswd) = @_; my ($privatedir, $opt_rootpasswd) = @_;
my $vmdir = $global_vzconf->{privatedir}; my $pwfile = "$privatedir/etc/passwd";
$vmdir =~ s/\$VEID/$vmid/;
my $pwfile = "$vmdir/etc/passwd";
return if ! -f $pwfile; return if ! -f $pwfile;
my $shadow = "$vmdir/etc/shadow"; my $shadow = "$privatedir/etc/shadow";
if ($opt_rootpasswd !~ m/^\$/) { if ($opt_rootpasswd !~ m/^\$/) {
my $time = substr (Digest::SHA1::sha1_base64 (time), 0, 8); my $time = substr (Digest::SHA1::sha1_base64 (time), 0, 8);
......
...@@ -564,6 +564,8 @@ Ext.define('PVE.Utils', { statics: { ...@@ -564,6 +564,8 @@ Ext.define('PVE.Utils', { statics: {
cta.push('Templates'); cta.push('Templates');
} else if (ct === 'iso') { } else if (ct === 'iso') {
cta.push('ISO'); cta.push('ISO');
} else if (ct === 'rootdir') {
cta.push('Containers');
} }
}); });
......
...@@ -5,12 +5,12 @@ Ext.define('PVE.form.ContentTypeSelector', { ...@@ -5,12 +5,12 @@ Ext.define('PVE.form.ContentTypeSelector', {
initComponent: function() { initComponent: function() {
var me = this; var me = this;
me.data = [ me.data = [];
['images', 'Images'],
['iso', 'ISO'], var cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir'];
['vztmpl', 'Templates'], Ext.Array.each(cts, function(ct) {
['backup', 'Backups'] me.data.push([ct, PVE.Utils.format_content_types(ct)]);
]; });
me.callParent(); me.callParent();
} }
......
...@@ -80,16 +80,23 @@ Ext.define('PVE.grid.BackupView', { ...@@ -80,16 +80,23 @@ Ext.define('PVE.grid.BackupView', {
text: 'Restore', text: 'Restore',
disabled: true, disabled: true,
selModel: sm, selModel: sm,
confirmMsg: function(rec) {
return 'Are you sure you want to restore from "' + rec.data.volid + '"? ' +
'This will permanently erase current VM data.';
},
enableFn: function(rec) { enableFn: function(rec) {
return !!rec; return !!rec;
}, },
handler: function(b, e, rec) { handler: function(b, e, rec) {
var volid = rec.data.volid; var volid = rec.data.volid;
var win = Ext.create('PVE.window.Restore', {
nodename: nodename,
vmid: vmid,
volid: rec.data.volid,
volidText: PVE.Utils.render_storage_content(rec.data.volid, {}, rec),
vmtype: vmtype
});
win.show();
win.on('destroy', reload);
return;
var url; var url;
var params = { var params = {
vmid: vmid, vmid: vmid,
......
...@@ -20,6 +20,14 @@ Ext.define('PVE.openvz.CreateWizard', { ...@@ -20,6 +20,14 @@ Ext.define('PVE.openvz.CreateWizard', {
] ]
}); });
var storagesel = Ext.create('PVE.form.StorageSelector', {
name: 'storage',
fieldLabel: 'Storage',
storageContent: 'rootdir',
autoSelect: true,
allowBlank: false
});
var tmplsel = Ext.create('PVE.form.FileSelector', { var tmplsel = Ext.create('PVE.form.FileSelector', {
name: 'ostemplate', name: 'ostemplate',
storageContent: 'vztmpl', storageContent: 'vztmpl',
...@@ -53,6 +61,7 @@ Ext.define('PVE.openvz.CreateWizard', { ...@@ -53,6 +61,7 @@ Ext.define('PVE.openvz.CreateWizard', {
change: function(f, value) { change: function(f, value) {
tmplsel.setStorage('local', value); tmplsel.setStorage('local', value);
bridgesel.setNodename(value); bridgesel.setNodename(value);
storagesel.setNodename(value);
} }
} }
}, },
...@@ -72,6 +81,7 @@ Ext.define('PVE.openvz.CreateWizard', { ...@@ -72,6 +81,7 @@ Ext.define('PVE.openvz.CreateWizard', {
} }
], ],
column2: [ column2: [
storagesel,
{ {
xtype: 'textfield', xtype: 'textfield',
inputType: 'password', inputType: 'password',
......
...@@ -42,9 +42,10 @@ Ext.define('PVE.window.Restore', { ...@@ -42,9 +42,10 @@ Ext.define('PVE.window.Restore', {
}, },
storagesel, storagesel,
{ {
xtype: 'pveVMIDSelector', xtype: me.vmid ? 'displayfield' : 'pveVMIDSelector',
name: 'vmid', name: 'vmid',
value: PVE.data.ResourceStore.findNextVMID(), fieldLabel: 'VM ID',
value: me.vmid || PVE.data.ResourceStore.findNextVMID(),
validateExists: false validateExists: false
} }
] ]
...@@ -56,6 +57,26 @@ Ext.define('PVE.window.Restore', { ...@@ -56,6 +57,26 @@ Ext.define('PVE.window.Restore', {
submitBtn.setDisabled(!valid); submitBtn.setDisabled(!valid);
}); });
var doRestore = function(url, params) {
PVE.Utils.API2Request({
url: url,
params: params,
method: 'POST',
failure: function (response, opts) {
Ext.Msg.alert('Error', response.htmlStatus);
},
success: function(response, options) {
var upid = response.result.data;
var win = Ext.create('PVE.window.TaskViewer', {
upid: upid
});
win.show();
me.close();
}
});
};
var submitBtn = Ext.create('Ext.Button', { var submitBtn = Ext.create('Ext.Button', {
text: 'Restore', text: 'Restore',
handler: function(){ handler: function(){
...@@ -64,36 +85,33 @@ Ext.define('PVE.window.Restore', { ...@@ -64,36 +85,33 @@ Ext.define('PVE.window.Restore', {
var params = { var params = {
storage: storage, storage: storage,
vmid: values.vmid vmid: me.vmid ? me.vmid : values.vmid,
force: me.vmid ? 1 : 0
}; };
if (me.vmtype === 'openvz') { if (me.vmtype === 'openvz') {
url = '/nodes/' + me.nodename + '/openvz'; url = '/nodes/' + me.nodename + '/openvz';
params.ostemplate = me.volid; params.ostemplate = me.volid;
params.restore = 1;
} else if (me.vmtype === 'qemu') { } else if (me.vmtype === 'qemu') {
url = '/nodes/' + me.nodename + '/qemu'; url = '/nodes/' + me.nodename + '/qemu';
params.archive = me.volid; params.archive = me.volid;
} else { } else {
throw 'unknown VM type'; throw 'unknown VM type';
} }
PVE.Utils.API2Request({ if (me.vmid) {
url: url, var msg = 'Are you sure you want to restore this VM"? ' +
params: params, 'This will permanently erase current VM data.';
method: 'POST', Ext.Msg.confirm('Confirmation', msg, function(btn) {
failure: function (response, opts) { if (btn !== 'yes') {
Ext.Msg.alert('Error',response.htmlStatus); return;
}, }
success: function(response, options) { doRestore(url, params);
var upid = response.result.data; });
} else {
var win = Ext.create('PVE.window.TaskViewer', { doRestore(url, params);
upid: upid }
});
win.show();
me.close();
}
});
} }
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment