It is now possible to use NFS or other directory type storages.
}});
my $restore_openvz = sub {
- my ($archive, $vmid, $force) = @_;
+ my ($private, $archive, $vmid, $force) = @_;
my $vzconf = PVE::OpenVZ::read_global_vz_config ();
my $conffile = PVE::OpenVZ::config_file($vmid);
my $cfgdir = dirname($conffile);
- my $private = $vzconf->{privatedir};
- $private =~ s/\$VEID/$vmid/;
my $root = $vzconf->{rootdir};
$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;
my $conf;
eval {
- rmtree $private if -d $private;
- rmtree $root if -d $root;
+ if ($force && -f $conffile) {
+ 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 $root || die "unable to create private dir '$private'";
type => 'string',
description => "Sets root password inside container.",
},
+ storage => get_standard_option('pve-storage-id', {
+ description => "Target storage.",
+ default => 'local',
+ optional => 1,
+ }),
force => {
optional => 1,
type => 'boolean',
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);
$archive = '-';
} else {
if (PVE::Storage::parse_volume_id($ostemplate, 1)) {
- $archive = PVE::Storage::path($stcfg, $ostemplate);
+ $archive = PVE::Storage::path($storage_cfg, $ostemplate);
} else {
raise_param_exc({ archive => "Only root can pass arbitrary paths." })
if $user ne 'root@pam';
$conf->{ostemplate}->{value} = $archive;
$conf->{ostemplate}->{value} =~ s|^.*/||;
$conf->{ostemplate}->{value} =~ s/\.tar\.(gz|bz2)$//;
+ $conf->{ve_private}->{value} = $private;
}
my $rawconf = PVE::OpenVZ::generate_raw_config($pve_base_ovz_config, $conf);
PVE::Cluster::check_cfs_quorum();
my $realcmd = sub {
- &$restore_openvz($archive, $vmid, $param->{force});
+ &$restore_openvz($private, $archive, $vmid, $param->{force});
PVE::Tools::file_set_contents($basecfg_fn, $rawconf)
if !$param->{restore};
# hack: vzctl '--userpasswd' starts the CT, but we want
# 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',
if (my $fh = IO::File->new ("/proc/mounts", "r")) {
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});
}
}
if (my $fh = IO::File->new ("/proc/vz/vzquota", "r")) {
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 $d = $list->{$vmid};
if ($d && defined($d->{status})) {
}
sub set_rootpasswd {
- my ($vmid, $opt_rootpasswd) = @_;
+ my ($privatedir, $opt_rootpasswd) = @_;
- my $vmdir = $global_vzconf->{privatedir};
- $vmdir =~ s/\$VEID/$vmid/;
-
- my $pwfile = "$vmdir/etc/passwd";
+ my $pwfile = "$privatedir/etc/passwd";
return if ! -f $pwfile;
- my $shadow = "$vmdir/etc/shadow";
+ my $shadow = "$privatedir/etc/shadow";
if ($opt_rootpasswd !~ m/^\$/) {
my $time = substr (Digest::SHA1::sha1_base64 (time), 0, 8);
cta.push('Templates');
} else if (ct === 'iso') {
cta.push('ISO');
+ } else if (ct === 'rootdir') {
+ cta.push('Containers');
}
});
initComponent: function() {
var me = this;
- me.data = [
- ['images', 'Images'],
- ['iso', 'ISO'],
- ['vztmpl', 'Templates'],
- ['backup', 'Backups']
- ];
+ me.data = [];
+
+ var cts = ['images', 'iso', 'vztmpl', 'backup', 'rootdir'];
+ Ext.Array.each(cts, function(ct) {
+ me.data.push([ct, PVE.Utils.format_content_types(ct)]);
+ });
me.callParent();
}
text: 'Restore',
disabled: true,
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) {
return !!rec;
},
handler: function(b, e, rec) {
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 params = {
vmid: vmid,
]
});
+ var storagesel = Ext.create('PVE.form.StorageSelector', {
+ name: 'storage',
+ fieldLabel: 'Storage',
+ storageContent: 'rootdir',
+ autoSelect: true,
+ allowBlank: false
+ });
+
var tmplsel = Ext.create('PVE.form.FileSelector', {
name: 'ostemplate',
storageContent: 'vztmpl',
change: function(f, value) {
tmplsel.setStorage('local', value);
bridgesel.setNodename(value);
+ storagesel.setNodename(value);
}
}
},
}
],
column2: [
+ storagesel,
{
xtype: 'textfield',
inputType: 'password',
},
storagesel,
{
- xtype: 'pveVMIDSelector',
+ xtype: me.vmid ? 'displayfield' : 'pveVMIDSelector',
name: 'vmid',
- value: PVE.data.ResourceStore.findNextVMID(),
+ fieldLabel: 'VM ID',
+ value: me.vmid || PVE.data.ResourceStore.findNextVMID(),
validateExists: false
}
]
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', {
text: 'Restore',
handler: function(){
var params = {
storage: storage,
- vmid: values.vmid
+ vmid: me.vmid ? me.vmid : values.vmid,
+ force: me.vmid ? 1 : 0
};
if (me.vmtype === 'openvz') {
url = '/nodes/' + me.nodename + '/openvz';
params.ostemplate = me.volid;
+ params.restore = 1;
} else if (me.vmtype === 'qemu') {
url = '/nodes/' + me.nodename + '/qemu';
params.archive = me.volid;
} else {
throw 'unknown VM type';
}
-
- 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();
- }
- });
+
+ if (me.vmid) {
+ var msg = 'Are you sure you want to restore this VM"? ' +
+ 'This will permanently erase current VM data.';
+ Ext.Msg.confirm('Confirmation', msg, function(btn) {
+ if (btn !== 'yes') {
+ return;
+ }
+ doRestore(url, params);
+ });
+ } else {
+ doRestore(url, params);
+ }
}
});