mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-09 16:12:18 +00:00
add openvz support (cli only for now)
This commit is contained in:
parent
2d2495d29d
commit
339e41597d
@ -5,7 +5,8 @@ PERLSOURCE = \
|
|||||||
Nodes.pm \
|
Nodes.pm \
|
||||||
Tasks.pm \
|
Tasks.pm \
|
||||||
Network.pm \
|
Network.pm \
|
||||||
Services.pm
|
Services.pm \
|
||||||
|
OpenVZ.pm
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ use PVE::API2::Tasks;
|
|||||||
use PVE::API2::Storage::Scan;
|
use PVE::API2::Storage::Scan;
|
||||||
use PVE::API2::Storage::Status;
|
use PVE::API2::Storage::Status;
|
||||||
use PVE::API2::Qemu;
|
use PVE::API2::Qemu;
|
||||||
|
use PVE::API2::OpenVZ;
|
||||||
use JSON;
|
use JSON;
|
||||||
|
|
||||||
use base qw(PVE::RESTHandler);
|
use base qw(PVE::RESTHandler);
|
||||||
@ -30,6 +31,11 @@ __PACKAGE__->register_method ({
|
|||||||
path => 'qemu',
|
path => 'qemu',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
__PACKAGE__->register_method ({
|
||||||
|
subclass => "PVE::API2::OpenVZ",
|
||||||
|
path => 'openvz',
|
||||||
|
});
|
||||||
|
|
||||||
__PACKAGE__->register_method ({
|
__PACKAGE__->register_method ({
|
||||||
subclass => "PVE::API2::Services",
|
subclass => "PVE::API2::Services",
|
||||||
path => 'services',
|
path => 'services',
|
||||||
@ -92,6 +98,7 @@ __PACKAGE__->register_method ({
|
|||||||
{ name => 'storage' },
|
{ name => 'storage' },
|
||||||
{ name => 'upload' },
|
{ name => 'upload' },
|
||||||
{ name => 'qemu' },
|
{ name => 'qemu' },
|
||||||
|
{ name => 'openvz' },
|
||||||
{ name => 'network' },
|
{ name => 'network' },
|
||||||
{ name => 'network_changes' },
|
{ name => 'network_changes' },
|
||||||
];
|
];
|
||||||
|
204
PVE/API2/OpenVZ.pm
Normal file
204
PVE/API2/OpenVZ.pm
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
package PVE::API2::OpenVZ;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
use PVE::SafeSyslog;
|
||||||
|
use PVE::Tools qw(extract_param);
|
||||||
|
use PVE::Cluster qw(cfs_lock_file cfs_read_file);
|
||||||
|
use PVE::Storage;
|
||||||
|
use PVE::RESTHandler;
|
||||||
|
use PVE::RPCEnvironment;
|
||||||
|
use PVE::OpenVZ;
|
||||||
|
use PVE::JSONSchema qw(get_standard_option);
|
||||||
|
|
||||||
|
use base qw(PVE::RESTHandler);
|
||||||
|
|
||||||
|
use Data::Dumper; # fixme: remove
|
||||||
|
|
||||||
|
my $pve_base_ovz_config = <<__EOD;
|
||||||
|
ONBOOT="no"
|
||||||
|
|
||||||
|
PHYSPAGES="0:256M"
|
||||||
|
SWAPPAGES="0:256M"
|
||||||
|
KMEMSIZE="116M:128M"
|
||||||
|
DCACHESIZE="58M:64M"
|
||||||
|
LOCKEDPAGES="128M"
|
||||||
|
PRIVVMPAGES="unlimited"
|
||||||
|
SHMPAGES="unlimited"
|
||||||
|
NUMPROC="unlimited"
|
||||||
|
VMGUARPAGES="0:unlimited"
|
||||||
|
OOMGUARPAGES="0:unlimited"
|
||||||
|
NUMTCPSOCK="unlimited"
|
||||||
|
NUMFLOCK="unlimited"
|
||||||
|
NUMPTY="unlimited"
|
||||||
|
NUMSIGINFO="unlimited"
|
||||||
|
TCPSNDBUF="unlimited"
|
||||||
|
TCPRCVBUF="unlimited"
|
||||||
|
OTHERSOCKBUF="unlimited"
|
||||||
|
DGRAMRCVBUF="unlimited"
|
||||||
|
NUMOTHERSOCK="unlimited"
|
||||||
|
NUMFILE="unlimited"
|
||||||
|
NUMIPTENT="unlimited"
|
||||||
|
|
||||||
|
# Disk quota parameters (in form of softlimit:hardlimit)
|
||||||
|
DISKSPACE="unlimited:unlimited"
|
||||||
|
DISKINODES="unlimited:unlimited"
|
||||||
|
QUOTATIME="0"
|
||||||
|
QUOTAUGIDLIMIT="0"
|
||||||
|
|
||||||
|
# CPU fair scheduler parameter
|
||||||
|
CPUUNITS="1000"
|
||||||
|
CPUS="1"
|
||||||
|
__EOD
|
||||||
|
|
||||||
|
|
||||||
|
my $get_config_path = sub {
|
||||||
|
my $vmid = shift;
|
||||||
|
return "/etc/pve/openvz/${vmid}.conf";
|
||||||
|
};
|
||||||
|
|
||||||
|
__PACKAGE__->register_method({
|
||||||
|
name => 'vmlist',
|
||||||
|
path => '',
|
||||||
|
method => 'GET',
|
||||||
|
description => "OpenVZ container index (per node).",
|
||||||
|
proxyto => 'node',
|
||||||
|
protected => 1, # openvz proc files are only readable by root
|
||||||
|
parameters => {
|
||||||
|
additionalProperties => 0,
|
||||||
|
properties => {
|
||||||
|
node => get_standard_option('pve-node'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
returns => {
|
||||||
|
type => 'array',
|
||||||
|
items => {
|
||||||
|
type => "object",
|
||||||
|
properties => {},
|
||||||
|
},
|
||||||
|
links => [ { rel => 'child', href => "{vmid}" } ],
|
||||||
|
},
|
||||||
|
code => sub {
|
||||||
|
my ($param) = @_;
|
||||||
|
|
||||||
|
my $vmstatus = PVE::OpenVZ::vmstatus();
|
||||||
|
|
||||||
|
return PVE::RESTHandler::hash_to_array($vmstatus, 'vmid');
|
||||||
|
|
||||||
|
}});
|
||||||
|
|
||||||
|
__PACKAGE__->register_method({
|
||||||
|
name => 'create_vm',
|
||||||
|
path => '',
|
||||||
|
method => 'POST',
|
||||||
|
description => "Create new container.",
|
||||||
|
protected => 1,
|
||||||
|
proxyto => 'node',
|
||||||
|
parameters => {
|
||||||
|
additionalProperties => 0,
|
||||||
|
properties => PVE::OpenVZ::json_config_properties({
|
||||||
|
node => get_standard_option('pve-node'),
|
||||||
|
vmid => get_standard_option('pve-vmid'),
|
||||||
|
ostemplate => {
|
||||||
|
description => "The OS template.",
|
||||||
|
type => 'string',
|
||||||
|
maxLength => 255,
|
||||||
|
},
|
||||||
|
password => {
|
||||||
|
optional => 1,
|
||||||
|
type => 'string',
|
||||||
|
description => "Sets root password inside container.",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
returns => { type => 'null'},
|
||||||
|
code => sub {
|
||||||
|
my ($param) = @_;
|
||||||
|
|
||||||
|
my $node = extract_param($param, 'node');
|
||||||
|
|
||||||
|
# fixme: fork worker?
|
||||||
|
|
||||||
|
my $vmid = extract_param($param, 'vmid');
|
||||||
|
|
||||||
|
my $password = extract_param($param, 'password');
|
||||||
|
|
||||||
|
my $stcfg = cfs_read_file("storage.cfg");
|
||||||
|
|
||||||
|
my $conf = PVE::OpenVZ::parse_ovz_config("/tmp/openvz/$vmid.conf", $pve_base_ovz_config);
|
||||||
|
|
||||||
|
my $code = sub {
|
||||||
|
|
||||||
|
my $basecfg_fn = &$get_config_path($vmid);
|
||||||
|
|
||||||
|
die "container $vmid already exists\n" if -f $basecfg_fn;
|
||||||
|
|
||||||
|
my $ostemplate = extract_param($param, 'ostemplate');
|
||||||
|
|
||||||
|
$ostemplate =~ s|^/var/lib/vz/template/cache/|local:vztmpl/|;
|
||||||
|
|
||||||
|
if ($ostemplate !~ m|^local:vztmpl/|) {
|
||||||
|
$ostemplate = "local:vztmpl/${ostemplate}";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $tpath = PVE::Storage::path($stcfg, $ostemplate);
|
||||||
|
die "can't find OS template '$ostemplate'\n" if ! -f $tpath;
|
||||||
|
|
||||||
|
# hack: openvz does not support full paths
|
||||||
|
$tpath = basename($tpath);
|
||||||
|
$tpath =~ s/\.tar\.gz$//;
|
||||||
|
|
||||||
|
PVE::OpenVZ::update_ovz_config($conf, $param);
|
||||||
|
|
||||||
|
my $rawconf = PVE::OpenVZ::generate_raw_config($pve_base_ovz_config, $conf);
|
||||||
|
|
||||||
|
PVE::Tools::file_set_contents($basecfg_fn, $rawconf);
|
||||||
|
|
||||||
|
my $cmd = ['vzctl', '--skiplock', 'create', $vmid, '--ostemplate', $tpath ];
|
||||||
|
|
||||||
|
PVE::Tools::run_command($cmd);
|
||||||
|
|
||||||
|
# hack: vzctl '--userpasswd' starts the CT, but we want
|
||||||
|
# to avoid that for create
|
||||||
|
PVE::OpenVZ::set_rootpasswd($vmid, $password) if defined($password);
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
};
|
||||||
|
|
||||||
|
PVE::OpenVZ::lock_container($vmid, $code);
|
||||||
|
}});
|
||||||
|
|
||||||
|
__PACKAGE__->register_method({
|
||||||
|
name => 'destroy_vm',
|
||||||
|
path => '{vmid}',
|
||||||
|
method => 'DELETE',
|
||||||
|
protected => 1,
|
||||||
|
proxyto => 'node',
|
||||||
|
description => "Destroy the container (also delete all uses files).",
|
||||||
|
parameters => {
|
||||||
|
additionalProperties => 0,
|
||||||
|
properties => {
|
||||||
|
node => get_standard_option('pve-node'),
|
||||||
|
vmid => get_standard_option('pve-vmid'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
returns => { type => 'null' },
|
||||||
|
code => sub {
|
||||||
|
my ($param) = @_;
|
||||||
|
|
||||||
|
my $rpcenv = PVE::RPCEnvironment::get();
|
||||||
|
|
||||||
|
my $user = $rpcenv->get_user();
|
||||||
|
|
||||||
|
my $vmid = $param->{vmid};
|
||||||
|
|
||||||
|
my $cmd = ['vzctl', 'destroy', $vmid ];
|
||||||
|
|
||||||
|
PVE::Tools::run_command($cmd);
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}});
|
||||||
|
|
||||||
|
1;
|
@ -7,6 +7,7 @@ PERLSOURCE = \
|
|||||||
API2Client.pm \
|
API2Client.pm \
|
||||||
APIDaemon.pm \
|
APIDaemon.pm \
|
||||||
REST.pm \
|
REST.pm \
|
||||||
|
OpenVZ.pm \
|
||||||
APLInfo.pm
|
APLInfo.pm
|
||||||
|
|
||||||
all: pvecfg.pm ${SUBDIRS}
|
all: pvecfg.pm ${SUBDIRS}
|
||||||
|
1018
PVE/OpenVZ.pm
1018
PVE/OpenVZ.pm
File diff suppressed because it is too large
Load Diff
14
bin/Makefile
14
bin/Makefile
@ -13,6 +13,7 @@ SCRIPTS = \
|
|||||||
pveperf
|
pveperf
|
||||||
|
|
||||||
MANS = \
|
MANS = \
|
||||||
|
pvectl.1 \
|
||||||
pvestatd.1 \
|
pvestatd.1 \
|
||||||
pvedaemon.1 \
|
pvedaemon.1 \
|
||||||
pveversion.1 \
|
pveversion.1 \
|
||||||
@ -20,8 +21,15 @@ MANS = \
|
|||||||
|
|
||||||
all: ${MANS}
|
all: ${MANS}
|
||||||
|
|
||||||
%.1: %
|
%.1: %.1.pod
|
||||||
pod2man -n $* -s 1 -r "proxmox ${VERSION}" -c "Proxmox Documentation" <$* >$*.1
|
rm -f $@
|
||||||
|
cat $<|pod2man -n $* -s 1 -r ${VERSION} -c "Proxmox Documentation" >$@
|
||||||
|
|
||||||
|
%.1.pod: %
|
||||||
|
podselect $*>$@
|
||||||
|
|
||||||
|
pvectl.1.pod: pvectl
|
||||||
|
perl -I.. ./pvectl printmanpod >$@
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
install: ${SCRIPTS} ${MANS}
|
install: ${SCRIPTS} ${MANS}
|
||||||
@ -38,5 +46,5 @@ distclean: clean
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf *~ ${MANS}
|
rm -rf *~ ${MANS} *.1.pod
|
||||||
set -e && for i in ${SUBDIRS}; do ${MAKE} -C $$i $@; done
|
set -e && for i in ${SUBDIRS}; do ${MAKE} -C $$i $@; done
|
||||||
|
546
bin/pvectl
Normal file → Executable file
546
bin/pvectl
Normal file → Executable file
@ -1,530 +1,76 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use Getopt::Long;
|
|
||||||
use PVE::Config;
|
|
||||||
use PVE::Utils;
|
|
||||||
use PVE::Storage;
|
|
||||||
use POSIX qw (LONG_MAX);
|
|
||||||
use File::stat;
|
|
||||||
use File::Basename;
|
|
||||||
|
|
||||||
# fixme: log actions with syslog
|
use PVE::Tools qw(extract_param);
|
||||||
# fixme: lock ve
|
use PVE::Cluster qw(cfs_register_file cfs_read_file);
|
||||||
|
use PVE::SafeSyslog;
|
||||||
|
use PVE::INotify;
|
||||||
|
use PVE::RPCEnvironment;
|
||||||
|
use PVE::CLIHandler;
|
||||||
|
use PVE::API2::OpenVZ;
|
||||||
|
|
||||||
my $vzdir = "/etc/vz";
|
use Data::Dumper; # fixme: remove
|
||||||
my $vzconf = "$vzdir/vz.conf";
|
|
||||||
my $confdir = "$vzdir/conf";
|
|
||||||
|
|
||||||
my $global_vzconf = read_glogal_vz_config ();
|
use base qw(PVE::CLIHandler);
|
||||||
|
|
||||||
# read global vz.conf
|
$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
|
||||||
sub read_glogal_vz_config {
|
|
||||||
|
|
||||||
local $/;
|
|
||||||
|
|
||||||
my $res = {
|
initlog('pvectl');
|
||||||
rootdir => '/var/lib/vz/root/$VEID',
|
|
||||||
privatedir => '/var/lib/vz/private/$VEID',
|
|
||||||
};
|
|
||||||
|
|
||||||
return $res if ! -f $vzconf;
|
|
||||||
|
|
||||||
open (TMP, "<$vzconf");
|
die "please run as root\n" if $> != 0;
|
||||||
my $data = <TMP> || '';
|
|
||||||
close (TMP);
|
|
||||||
|
|
||||||
if ($data =~ m/^\s*VE_PRIVATE=\s*(.*\S)\s*$/m) {
|
PVE::INotify::inotify_init();
|
||||||
my $dir = $1;
|
my $nodename = PVE::INotify::nodename();
|
||||||
$dir =~ s/^\"(.*)\"/$1/;
|
|
||||||
$res->{privatedir} = $dir;
|
|
||||||
}
|
|
||||||
if ($data =~ m/^\s*VE_ROOT=\s*(.*\S)\s*$/m) {
|
|
||||||
my $dir = $1;
|
|
||||||
$dir =~ s/^\"(.*)\"/$1/;
|
|
||||||
$res->{rootdir} = $dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $res;
|
my $rpcenv = PVE::RPCEnvironment->init('cli');
|
||||||
}
|
|
||||||
|
|
||||||
sub get_private_dir {
|
$rpcenv->init_request();
|
||||||
my $veid = shift;
|
$rpcenv->set_language($ENV{LANG});
|
||||||
|
$rpcenv->set_user('root@pam');
|
||||||
|
|
||||||
my $res = $global_vzconf->{privatedir};
|
my $cmddef = {
|
||||||
|
|
||||||
$res =~ s/\$VEID/$veid/;
|
list => [ "PVE::API2::OpenVZ", 'vmlist', [],
|
||||||
|
{ node => $nodename }, sub {
|
||||||
|
my $vmlist = shift;
|
||||||
|
|
||||||
return $res;
|
exit 0 if (!scalar(@$vmlist));
|
||||||
}
|
|
||||||
|
|
||||||
sub replacepw {
|
printf "%10s %-20s %-10s %-10s %12s %-10s\n",
|
||||||
my ($file, $epw) = @_;
|
qw(VMID NAME STATUS MEM(MB) DISK(GB));
|
||||||
|
|
||||||
my $tmpfile = "$file.$$";
|
foreach my $rec (sort { $a->{vmid} <=> $b->{vmid} } @$vmlist) {
|
||||||
|
printf "%10s %-20s %-10s %-10s %-12.2f\n", $rec->{vmid}, $rec->{name} || '',
|
||||||
|
$rec->{status},
|
||||||
|
($rec->{maxmem} || 0)/(1024*1024),
|
||||||
|
($rec->{maxdisk} || 0)/(1024*1024*1024);
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
|
||||||
eval {
|
create => [ 'PVE::API2::OpenVZ', 'create_vm', ['vmid', 'ostemplate'], { node => $nodename } ],
|
||||||
open (SRC, "<$file") ||
|
destroy => [ 'PVE::API2::OpenVZ', 'destroy_vm', ['vmid'], { node => $nodename } ],
|
||||||
die "unable to open file '$file' - $!";
|
|
||||||
|
|
||||||
my $st = stat (\*SRC) ||
|
};
|
||||||
die "unable to stat file - $!";
|
|
||||||
|
|
||||||
open (DST, ">$tmpfile") ||
|
my $cmd = shift;
|
||||||
die "unable to open file '$tmpfile' - $!";
|
|
||||||
|
|
||||||
# copy owner and permissions
|
PVE::CLIHandler::handle_cmd($cmddef, "pvectl", $cmd, \@ARGV, undef, $0);
|
||||||
chmod $st->mode, \*DST;
|
|
||||||
chown $st->uid, $st->gid, \*DST;
|
|
||||||
|
|
||||||
while (defined (my $line = <SRC>)) {
|
|
||||||
$line =~ s/^root:[^:]*:/root:${epw}:/;
|
|
||||||
print DST $line;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
my $err = $@;
|
exit 0;
|
||||||
|
|
||||||
close (SRC);
|
__END__
|
||||||
close (DST);
|
|
||||||
|
|
||||||
if ($err) {
|
=head1 NAME
|
||||||
unlink $tmpfile;
|
|
||||||
} else {
|
|
||||||
rename $tmpfile, $file;
|
|
||||||
unlink $tmpfile; # in case rename fails
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_rootpasswd {
|
pvectl - vzctl wrapper to manage OpenVZ containers
|
||||||
my ($vmdir, $opt_rootpasswd) = @_;
|
|
||||||
|
|
||||||
my $pwfile = "$vmdir/etc/passwd";
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
return if ! -f $pwfile;
|
=include synopsis
|
||||||
|
|
||||||
my $shadow = "$vmdir/etc/shadow";
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
if (-f $shadow) {
|
This is a small wrapper around vztl.
|
||||||
replacepw ($shadow, $opt_rootpasswd);
|
|
||||||
replacepw ($pwfile, 'x');
|
|
||||||
} else {
|
|
||||||
replacepw ($pwfile, $opt_rootpasswd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub print_usage {
|
=include pve_copyright
|
||||||
my ($msg) = @_;
|
|
||||||
|
|
||||||
if ($msg) {
|
|
||||||
print STDERR "ERROR: $msg\n";
|
|
||||||
}
|
|
||||||
print STDERR "pvectl <command> <vmid> [parameters]\n";
|
|
||||||
print STDERR "pvectl [vzcreate|vzset] <vmid> (openvz commands)\n";
|
|
||||||
print STDERR " --ostemplate NAME specify OS template\n";
|
|
||||||
print STDERR " --mem MBYTES memory in MB (64 - 8192)\n";
|
|
||||||
print STDERR " --swap MBYTES swap memory in MB (0 - 8192)\n";
|
|
||||||
print STDERR " --disk GBYTE disk space in GB (0.5 - 1024)\n";
|
|
||||||
print STDERR " --cpus N cpus (1 - 4)\n";
|
|
||||||
print STDERR " --cpuunits N cpu units (8 - 500000)\n";
|
|
||||||
print STDERR " --onboot [yes|no] start at boot\n";
|
|
||||||
print STDERR "pvectl print <vmid>\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scalar (@ARGV) == 0) {
|
|
||||||
print_usage ();
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $cmd = shift @ARGV;
|
|
||||||
|
|
||||||
if (scalar (@ARGV) == 0) {
|
|
||||||
print_usage ();
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $vmid = shift @ARGV;
|
|
||||||
|
|
||||||
if ($vmid !~ m/^\d+$/) {
|
|
||||||
print_usage ("unable to parse <vmid>");
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# test if barrier or limit changed
|
|
||||||
sub push_bl_changes {
|
|
||||||
my ($veconf, $changes, $name, $bar, $lim) = @_;
|
|
||||||
|
|
||||||
if (!defined ($veconf->{$name}->{bar}) || $veconf->{$name}->{bar} != $bar ||
|
|
||||||
!defined ($veconf->{$name}->{lim}) || $veconf->{$name}->{lim} != $lim) {
|
|
||||||
$veconf->{$name}->{bar} = $bar;
|
|
||||||
$veconf->{$name}->{lim} = $lim;
|
|
||||||
push @$changes, "--$name", "$bar:$lim";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# we use lockedpages to store 'swap' settings - this is not really correct,
|
|
||||||
# but its better than nothing.
|
|
||||||
|
|
||||||
sub change_veconfig {
|
|
||||||
my ($veconf, $param) = @_;
|
|
||||||
|
|
||||||
my $changes = [];
|
|
||||||
|
|
||||||
my $mem = int (($veconf->{vmguarpages}->{bar} * 4) / 1024);
|
|
||||||
my $disk = $veconf->{diskspace}->{bar} / (1024*1024);
|
|
||||||
my $cpuunits = $veconf->{cpuunits}->{value} || 1000;
|
|
||||||
my $quotatime = $veconf->{quotatime}->{value} || 0;
|
|
||||||
my $quotaugidlimit = $veconf->{quotaugidlimit}->{value} || 0;
|
|
||||||
my $cpus = $veconf->{cpus}->{value} || 1;
|
|
||||||
|
|
||||||
my $swdiff = $veconf->{vmguarpages}->{bar} - $veconf->{lockedpages}->{bar};
|
|
||||||
my $swap = $swdiff > 0 ? int (($swdiff * 4) / 1024) : 0;
|
|
||||||
my $phymem = $mem - $swap;
|
|
||||||
|
|
||||||
if ($param->{mem}) {
|
|
||||||
$phymem = $param->{mem};
|
|
||||||
}
|
|
||||||
if (defined ($param->{swap})) {
|
|
||||||
$swap = $param->{swap};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($param->{disk}) {
|
|
||||||
$disk = $param->{disk};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($param->{cpuunits}) {
|
|
||||||
$cpuunits = $param->{cpuunits};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined($param->{quotatime})) {
|
|
||||||
$quotatime = $param->{quotatime};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined($param->{quotaugidlimit})) {
|
|
||||||
$quotaugidlimit = $param->{quotaugidlimit};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($param->{cpus}) {
|
|
||||||
$cpus = $param->{cpus};
|
|
||||||
}
|
|
||||||
|
|
||||||
$mem = $phymem + $swap;
|
|
||||||
|
|
||||||
# memory related parameter
|
|
||||||
|
|
||||||
my $vmguarpages = int ($mem*1024/4);
|
|
||||||
push_bl_changes ($veconf, $changes, 'vmguarpages', $vmguarpages, LONG_MAX);
|
|
||||||
|
|
||||||
my $privmax = int ($vmguarpages*1.1);
|
|
||||||
$privmax = $vmguarpages + 12500 if ($privmax - $vmguarpages) > 12500;
|
|
||||||
|
|
||||||
push_bl_changes ($veconf, $changes, 'oomguarpages', $vmguarpages, LONG_MAX);
|
|
||||||
push_bl_changes ($veconf, $changes, 'privvmpages', $vmguarpages, $privmax);
|
|
||||||
|
|
||||||
my $lockedpages;
|
|
||||||
if ($swap) {
|
|
||||||
$lockedpages = int (($mem - $swap)*1024/4);
|
|
||||||
} else {
|
|
||||||
$lockedpages = LONG_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
push_bl_changes ($veconf, $changes, 'lockedpages', $lockedpages, $lockedpages);
|
|
||||||
|
|
||||||
# disk quota parameters
|
|
||||||
|
|
||||||
my $diskspace = int ($disk * 1024 * 1024);
|
|
||||||
my $diskspace_lim = int ($diskspace * 1.1);
|
|
||||||
push_bl_changes ($veconf, $changes, 'diskspace', $diskspace, $diskspace_lim);
|
|
||||||
|
|
||||||
my $diskinodes = int ($disk * 200000);
|
|
||||||
my $diskinodes_lim = int ($disk * 220000);
|
|
||||||
push_bl_changes ($veconf, $changes, 'diskinodes', $diskinodes, $diskinodes_lim);
|
|
||||||
|
|
||||||
# cpu settings
|
|
||||||
|
|
||||||
if ($veconf->{'cpuunits'}->{value} != $cpuunits) {
|
|
||||||
push @$changes, '--cpuunits', "$cpuunits";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($veconf->{'quotatime'}->{value} != $quotatime) {
|
|
||||||
push @$changes, '--quotatime', "$quotatime";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($veconf->{'quotaugidlimit'}->{value} != $quotaugidlimit) {
|
|
||||||
push @$changes, '--quotaugidlimit', "$quotaugidlimit";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($veconf->{'cpus'}->{value} != $cpus) {
|
|
||||||
push @$changes, '--cpus', "$cpus";
|
|
||||||
}
|
|
||||||
|
|
||||||
#foreach my $nv (@$changes) {
|
|
||||||
#print "CHANGE: $nv\n";
|
|
||||||
#}
|
|
||||||
|
|
||||||
return $changes;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub test_pve_config {
|
|
||||||
my ($veconf) = @_;
|
|
||||||
|
|
||||||
my $osample = $veconf->{origin_sample}->{value} || 'not set';
|
|
||||||
if ($osample ne 'pve.auto') {
|
|
||||||
print STDERR "VE $vmid is not managed by PVE (origin sample is $osample)\n";
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $opt_mem;
|
|
||||||
my $opt_swap;
|
|
||||||
my $opt_disk;
|
|
||||||
my $opt_cpus;
|
|
||||||
my $opt_cpuunits;
|
|
||||||
my $opt_quotatime;
|
|
||||||
my $opt_quotaugidlimit;
|
|
||||||
my $opt_ostemplate;
|
|
||||||
my $opt_ipset;
|
|
||||||
my $opt_hostname;
|
|
||||||
my $opt_nameserver;
|
|
||||||
my $opt_searchdomain;
|
|
||||||
my $opt_onboot;
|
|
||||||
my $opt_netif;
|
|
||||||
my $opt_rootpasswd;
|
|
||||||
my $opt_description;
|
|
||||||
|
|
||||||
my $stcfg = PVE::Storage::load_config();
|
|
||||||
|
|
||||||
if ($cmd eq 'vzcreate' || $cmd eq 'vzset') {
|
|
||||||
|
|
||||||
if (!GetOptions ('mem=i' => \$opt_mem,
|
|
||||||
'swap=i' => \$opt_swap,
|
|
||||||
'disk=f' => \$opt_disk,
|
|
||||||
'cpus=i' => \$opt_cpus,
|
|
||||||
'cpuunits=i' => \$opt_cpuunits,
|
|
||||||
'quotatime=i' => \$opt_quotatime,
|
|
||||||
'quotaugidlimit=i' => \$opt_quotaugidlimit,
|
|
||||||
'ipset=s' => \$opt_ipset,
|
|
||||||
'hostname=s' => \$opt_hostname,
|
|
||||||
'description=s' => \$opt_description,
|
|
||||||
'searchdomain=s' => \$opt_searchdomain,
|
|
||||||
'nameserver=s@' => \$opt_nameserver,
|
|
||||||
'onboot=s' => \$opt_onboot,
|
|
||||||
'netif=s' => \$opt_netif,
|
|
||||||
'rootpasswd=s' => \$opt_rootpasswd,
|
|
||||||
'ostemplate=s' => \$opt_ostemplate)) {
|
|
||||||
|
|
||||||
print_usage ();
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
PVE::Utils::check_vm_settings ({
|
|
||||||
mem => $opt_mem,
|
|
||||||
swap => $opt_swap,
|
|
||||||
disk => $opt_disk,
|
|
||||||
onboot => $opt_onboot,
|
|
||||||
cpuunits => $opt_cpuunits,
|
|
||||||
cpus => $opt_cpus });
|
|
||||||
|
|
||||||
if ($cmd eq 'vzcreate') {
|
|
||||||
|
|
||||||
if (!$opt_ostemplate) {
|
|
||||||
die "no --ostemplate specified\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($opt_ostemplate !~ m![/:]!) {
|
|
||||||
$opt_ostemplate = "local:vztmpl/${opt_ostemplate}";
|
|
||||||
}
|
|
||||||
|
|
||||||
my (undef, $volid) = PVE::Storage::path_to_volume_id ($stcfg, $opt_ostemplate);
|
|
||||||
die "can't find OS template '$opt_ostemplate'\n" if !$volid;
|
|
||||||
|
|
||||||
my $tpath = PVE::Storage::path ($stcfg, $volid);
|
|
||||||
|
|
||||||
die "can't find OS template '$opt_ostemplate'\n" if ! -f $tpath;
|
|
||||||
|
|
||||||
# hack: openvz does not support full paths
|
|
||||||
$tpath = basename ($tpath);
|
|
||||||
$tpath =~ s/\.tar\.gz$//;
|
|
||||||
|
|
||||||
if (-f "$confdir/${vmid}.conf") {
|
|
||||||
print STDERR "VE $vmid already exists\n";
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $cmd = ['vzctl', 'create', $vmid, '--ostemplate', $tpath,
|
|
||||||
'--config', 'pve.auto'];
|
|
||||||
eval {
|
|
||||||
my $out = PVE::Utils::run_command ($cmd);
|
|
||||||
};
|
|
||||||
|
|
||||||
my $err = $@;
|
|
||||||
|
|
||||||
if ($err) {
|
|
||||||
print STDERR "unable to create VE $vmid: $err\n";
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (defined ($opt_ostemplate)) {
|
|
||||||
print_usage ("unable to set --ostemplate");
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
# test existence
|
|
||||||
if (! -f "$confdir/${vmid}.conf") {
|
|
||||||
print STDERR "VE $vmid does not exist\n";
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined ($opt_rootpasswd)) {
|
|
||||||
print_usage ("option --rootpasswd not allowed");
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my $veconf = PVE::Config::get_veconfig ($vmid);
|
|
||||||
|
|
||||||
test_pve_config ($veconf);
|
|
||||||
|
|
||||||
my $changes = change_veconfig ($veconf, {
|
|
||||||
mem => $opt_mem,
|
|
||||||
swap => $opt_swap,
|
|
||||||
cpus => $opt_cpus,
|
|
||||||
cpuunits => $opt_cpuunits,
|
|
||||||
quotatime => $opt_quotatime,
|
|
||||||
quotaugidlimit => $opt_quotaugidlimit,
|
|
||||||
disk => $opt_disk});
|
|
||||||
|
|
||||||
if ($opt_hostname) {
|
|
||||||
push @$changes, '--hostname', $opt_hostname;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined ($opt_description)) {
|
|
||||||
push @$changes, '--description', $opt_description;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($opt_searchdomain) {
|
|
||||||
push @$changes, '--searchdomain', $opt_searchdomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined ($opt_ipset)) {
|
|
||||||
my $iphash = {};
|
|
||||||
if (defined ($veconf->{ip_address}) &&
|
|
||||||
$veconf->{ip_address}->{value}) {
|
|
||||||
foreach my $ip (split (/\s+/, $veconf->{ip_address}->{value})) {
|
|
||||||
$iphash->{$ip} = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
my $newhash = {};
|
|
||||||
foreach my $ip (split (/\s*[,;\s]\s*/, $opt_ipset)) {
|
|
||||||
next if $ip !~ m/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
|
||||||
$newhash->{$ip} = 1;
|
|
||||||
if (!$iphash->{$ip}) {
|
|
||||||
push @$changes, '--ipadd', $ip;
|
|
||||||
$iphash->{$ip} = 1; # only add once
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach my $ip (keys %$iphash) {
|
|
||||||
if (!$newhash->{$ip}) {
|
|
||||||
push @$changes, '--ipdel', $ip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined ($opt_netif)) {
|
|
||||||
my $ifaces = {};
|
|
||||||
if (defined ($veconf->{netif}) &&
|
|
||||||
$veconf->{netif}->{value}) {
|
|
||||||
|
|
||||||
$ifaces = PVE::Config::parse_netif ($veconf->{netif}->{value});
|
|
||||||
}
|
|
||||||
my $newif = PVE::Config::parse_netif ($opt_netif);
|
|
||||||
|
|
||||||
foreach my $ifname (sort keys %$ifaces) {
|
|
||||||
if (!$newif->{$ifname}) {
|
|
||||||
push @$changes, '--netif_del', $ifname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $ifname (sort keys %$newif) {
|
|
||||||
my $param = $ifname;
|
|
||||||
$param .= $newif->{$ifname}->{mac} ? ",$newif->{$ifname}->{mac}" : ',';
|
|
||||||
$param .= $newif->{$ifname}->{host_ifname} ? ",$newif->{$ifname}->{host_ifname}" : ',';
|
|
||||||
$param .= $newif->{$ifname}->{host_mac} ? ",$newif->{$ifname}->{host_mac}" : ',';
|
|
||||||
$param .= $newif->{$ifname}->{bridge} ? ",$newif->{$ifname}->{bridge}" : '';
|
|
||||||
|
|
||||||
if (!$ifaces->{$ifname} || ($ifaces->{$ifname}->{raw} ne $newif->{$ifname}->{raw})) {
|
|
||||||
push @$changes, '--netif_add', $param;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($opt_onboot) {
|
|
||||||
push @$changes, '--onboot', $opt_onboot;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $ns (@$opt_nameserver) {
|
|
||||||
push @$changes, '--nameserver', $ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($opt_rootpasswd) {
|
|
||||||
# hack: vzctl '--userpasswd' starts the CT, but we want to avoid that
|
|
||||||
# for create
|
|
||||||
if ($cmd eq 'vzcreate') {
|
|
||||||
my $vmdir = get_private_dir ($vmid);
|
|
||||||
set_rootpasswd ($vmdir, $opt_rootpasswd);
|
|
||||||
} else {
|
|
||||||
die "internal error"; # should not be reached
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scalar (@$changes) <= 0) {
|
|
||||||
exit (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
my @cmd = ('vzctl', 'set', $vmid, @$changes, '--save');
|
|
||||||
|
|
||||||
my $cmdstr = join (' ', @cmd);
|
|
||||||
print "$cmdstr\n";
|
|
||||||
|
|
||||||
if (system (@cmd) != 0) {
|
|
||||||
print STDERR "unable to set parameters - command failed - $?\n";
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} elsif ($cmd eq 'print') {
|
|
||||||
|
|
||||||
if (scalar (@ARGV) != 0) {
|
|
||||||
print_usage ();
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $veconf = PVE::Config::get_veconfig ($vmid);
|
|
||||||
|
|
||||||
test_pve_config ($veconf);
|
|
||||||
|
|
||||||
print "Resource settings for VE $vmid:\n";
|
|
||||||
my $mem = int (($veconf->{vmguarpages}->{bar} * 4) / 1024);
|
|
||||||
|
|
||||||
my $swdiff = $veconf->{vmguarpages}->{bar} - $veconf->{lockedpages}->{bar};
|
|
||||||
my $swap = $swdiff > 0 ? int (($swdiff * 4) / 1024) : 0;
|
|
||||||
$mem = $mem - $swap;
|
|
||||||
|
|
||||||
print "Memory: $mem MB\n";
|
|
||||||
|
|
||||||
print "SWAP: $swap MB\n";
|
|
||||||
|
|
||||||
my $disk = $veconf->{diskspace}->{bar} / (1024*1024);
|
|
||||||
|
|
||||||
printf "Disk Space: %0.2f GB\n", $disk;
|
|
||||||
|
|
||||||
my $cpu = $veconf->{cpuunits}->{value};
|
|
||||||
|
|
||||||
print "CPU Units: $cpu\n";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
print_usage ("no such command '$cmd'");
|
|
||||||
exit (-1);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user