mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-06 10:42:21 +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 \
|
||||
Tasks.pm \
|
||||
Network.pm \
|
||||
Services.pm
|
||||
Services.pm \
|
||||
OpenVZ.pm
|
||||
|
||||
all:
|
||||
|
||||
|
@ -21,6 +21,7 @@ use PVE::API2::Tasks;
|
||||
use PVE::API2::Storage::Scan;
|
||||
use PVE::API2::Storage::Status;
|
||||
use PVE::API2::Qemu;
|
||||
use PVE::API2::OpenVZ;
|
||||
use JSON;
|
||||
|
||||
use base qw(PVE::RESTHandler);
|
||||
@ -30,6 +31,11 @@ __PACKAGE__->register_method ({
|
||||
path => 'qemu',
|
||||
});
|
||||
|
||||
__PACKAGE__->register_method ({
|
||||
subclass => "PVE::API2::OpenVZ",
|
||||
path => 'openvz',
|
||||
});
|
||||
|
||||
__PACKAGE__->register_method ({
|
||||
subclass => "PVE::API2::Services",
|
||||
path => 'services',
|
||||
@ -92,6 +98,7 @@ __PACKAGE__->register_method ({
|
||||
{ name => 'storage' },
|
||||
{ name => 'upload' },
|
||||
{ name => 'qemu' },
|
||||
{ name => 'openvz' },
|
||||
{ name => 'network' },
|
||||
{ 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 \
|
||||
APIDaemon.pm \
|
||||
REST.pm \
|
||||
OpenVZ.pm \
|
||||
APLInfo.pm
|
||||
|
||||
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
|
||||
|
||||
MANS = \
|
||||
pvectl.1 \
|
||||
pvestatd.1 \
|
||||
pvedaemon.1 \
|
||||
pveversion.1 \
|
||||
@ -20,8 +21,15 @@ MANS = \
|
||||
|
||||
all: ${MANS}
|
||||
|
||||
%.1: %
|
||||
pod2man -n $* -s 1 -r "proxmox ${VERSION}" -c "Proxmox Documentation" <$* >$*.1
|
||||
%.1: %.1.pod
|
||||
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
|
||||
install: ${SCRIPTS} ${MANS}
|
||||
@ -38,5 +46,5 @@ distclean: clean
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *~ ${MANS}
|
||||
rm -rf *~ ${MANS} *.1.pod
|
||||
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
|
||||
|
||||
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
|
||||
# fixme: lock ve
|
||||
use PVE::Tools qw(extract_param);
|
||||
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";
|
||||
my $vzconf = "$vzdir/vz.conf";
|
||||
my $confdir = "$vzdir/conf";
|
||||
use Data::Dumper; # fixme: remove
|
||||
|
||||
my $global_vzconf = read_glogal_vz_config ();
|
||||
use base qw(PVE::CLIHandler);
|
||||
|
||||
# read global vz.conf
|
||||
sub read_glogal_vz_config {
|
||||
|
||||
local $/;
|
||||
$ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
|
||||
|
||||
my $res = {
|
||||
rootdir => '/var/lib/vz/root/$VEID',
|
||||
privatedir => '/var/lib/vz/private/$VEID',
|
||||
};
|
||||
|
||||
return $res if ! -f $vzconf;
|
||||
initlog('pvectl');
|
||||
|
||||
open (TMP, "<$vzconf");
|
||||
my $data = <TMP> || '';
|
||||
close (TMP);
|
||||
die "please run as root\n" if $> != 0;
|
||||
|
||||
if ($data =~ m/^\s*VE_PRIVATE=\s*(.*\S)\s*$/m) {
|
||||
my $dir = $1;
|
||||
$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;
|
||||
}
|
||||
PVE::INotify::inotify_init();
|
||||
my $nodename = PVE::INotify::nodename();
|
||||
|
||||
return $res;
|
||||
}
|
||||
my $rpcenv = PVE::RPCEnvironment->init('cli');
|
||||
|
||||
sub get_private_dir {
|
||||
my $veid = shift;
|
||||
$rpcenv->init_request();
|
||||
$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 {
|
||||
my ($file, $epw) = @_;
|
||||
printf "%10s %-20s %-10s %-10s %12s %-10s\n",
|
||||
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 {
|
||||
open (SRC, "<$file") ||
|
||||
die "unable to open file '$file' - $!";
|
||||
create => [ 'PVE::API2::OpenVZ', 'create_vm', ['vmid', 'ostemplate'], { node => $nodename } ],
|
||||
destroy => [ 'PVE::API2::OpenVZ', 'destroy_vm', ['vmid'], { node => $nodename } ],
|
||||
|
||||
my $st = stat (\*SRC) ||
|
||||
die "unable to stat file - $!";
|
||||
};
|
||||
|
||||
open (DST, ">$tmpfile") ||
|
||||
die "unable to open file '$tmpfile' - $!";
|
||||
my $cmd = shift;
|
||||
|
||||
# copy owner and permissions
|
||||
chmod $st->mode, \*DST;
|
||||
chown $st->uid, $st->gid, \*DST;
|
||||
|
||||
while (defined (my $line = <SRC>)) {
|
||||
$line =~ s/^root:[^:]*:/root:${epw}:/;
|
||||
print DST $line;
|
||||
}
|
||||
};
|
||||
PVE::CLIHandler::handle_cmd($cmddef, "pvectl", $cmd, \@ARGV, undef, $0);
|
||||
|
||||
my $err = $@;
|
||||
exit 0;
|
||||
|
||||
close (SRC);
|
||||
close (DST);
|
||||
__END__
|
||||
|
||||
if ($err) {
|
||||
unlink $tmpfile;
|
||||
} else {
|
||||
rename $tmpfile, $file;
|
||||
unlink $tmpfile; # in case rename fails
|
||||
}
|
||||
}
|
||||
=head1 NAME
|
||||
|
||||
sub set_rootpasswd {
|
||||
my ($vmdir, $opt_rootpasswd) = @_;
|
||||
pvectl - vzctl wrapper to manage OpenVZ containers
|
||||
|
||||
my $pwfile = "$vmdir/etc/passwd";
|
||||
=head1 SYNOPSIS
|
||||
|
||||
return if ! -f $pwfile;
|
||||
=include synopsis
|
||||
|
||||
my $shadow = "$vmdir/etc/shadow";
|
||||
=head1 DESCRIPTION
|
||||
|
||||
if (-f $shadow) {
|
||||
replacepw ($shadow, $opt_rootpasswd);
|
||||
replacepw ($pwfile, 'x');
|
||||
} else {
|
||||
replacepw ($pwfile, $opt_rootpasswd);
|
||||
}
|
||||
}
|
||||
This is a small wrapper around vztl.
|
||||
|
||||
sub print_usage {
|
||||
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);
|
||||
}
|
||||
=include pve_copyright
|
||||
|
Loading…
Reference in New Issue
Block a user