]>
git.proxmox.com Git - pve-container.git/blob - src/PVE/LXC.pm
9 use PVE
:: Cluster
qw(cfs_register_file cfs_read_file) ;
12 use PVE
:: JSONSchema
qw(get_standard_option) ;
13 use PVE
:: Tools
qw( $IPV6RE $IPV4RE ) ;
17 cfs_register_file
( '/lxc/' , \
& parse_lxc_config
, \
& write_lxc_config
);
19 PVE
:: JSONSchema
:: register_format
( 'pve-lxc-network' , \
& verify_lxc_network
);
20 sub verify_lxc_network
{
21 my ( $value, $noerr ) = @_ ;
23 return $value if parse_lxc_network
( $value );
25 return undef if $noerr ;
27 die "unable to parse network setting \n " ;
30 my $nodename = PVE
:: INotify
:: nodename
();
33 my ( $name, $value ) = @_ ;
35 if ( $value =~ m/^(\d+)(b|k|m|g)?$/i ) {
36 my ( $res, $unit ) = ( $1, lc ( $2 || 'b' ));
38 return $res if $unit eq 'b' ;
39 return $res*1024 if $unit eq 'k' ;
40 return $res*1024*1024 if $unit eq 'm' ;
41 return $res*1024*1024*1024 if $unit eq 'g' ;
47 my $valid_lxc_keys = {
48 'lxc.arch' => 'i386|x86|i686|x86_64|amd64' ,
56 'lxc.cgroup.memory.limit_in_bytes' => \
& parse_lxc_size
,
57 'lxc.cgroup.memory.memsw.limit_in_bytes' => \
& parse_lxc_size
,
58 'lxc.cgroup.cpu.cfs_period_us' => '\d+' ,
59 'lxc.cgroup.cpu.cfs_quota_us' => '\d+' ,
60 'lxc.cgroup.cpu.shares' => '\d+' ,
64 'lxc.mount.entry' => 1 ,
65 'lxc.mount.auto' => 1 ,
70 'lxc.haltsignal' => 1 ,
71 'lxc.rebootsignal' => 1 ,
72 'lxc.stopsignal' => 1 ,
75 'lxc.console.logfile' => 1 ,
81 'lxc.aa_profile' => 1 ,
82 'lxc.aa_allow_incomplete' => 1 ,
83 'lxc.se_context' => 1 ,
86 'lxc.environment' => 1 ,
90 'lxc.start.auto' => 1 ,
91 'lxc.start.delay' => 1 ,
92 'lxc.start.order' => 1 ,
96 'lxc.hook.pre-start' => 1 ,
97 'lxc.hook.pre-mount' => 1 ,
98 'lxc.hook.mount' => 1 ,
99 'lxc.hook.autodev' => 1 ,
100 'lxc.hook.start' => 1 ,
101 'lxc.hook.post-stop' => 1 ,
102 'lxc.hook.clone' => 1 ,
105 'pve.nameserver' => sub {
106 my ( $name, $value ) = @_ ;
107 return verify_nameserver_list
( $value );
109 'pve.searchdomain' => sub {
110 my ( $name, $value ) = @_ ;
111 return verify_searchdomain_list
( $value );
113 'pve.onboot' => '(0|1)' ,
114 'pve.startup' => sub {
115 my ( $name, $value ) = @_ ;
116 return PVE
:: JSONSchema
:: pve_verify_startup_order
( $value );
119 'pve.disksize' => '\d+(\.\d+)?' ,
122 my $valid_lxc_network_keys = {
125 name
=> 1 , # ifname inside container
126 'veth.pair' => 1 , # ifname at host (eth${vmid}.X)
130 my $valid_pve_network_keys = {
140 my $lxc_array_configs = {
147 sub write_lxc_config
{
148 my ( $filename, $data ) = @_ ;
152 return $raw if ! $data ;
154 my $done_hash = { digest
=> 1 };
156 foreach my $k ( sort keys %$data ) {
157 next if $k !~ m/^lxc\./ ;
158 $done_hash ->{ $k } = 1 ;
159 if ( ref ( $data ->{ $k })) {
160 die "got unexpected reference for ' $k '" if ! $lxc_array_configs ->{ $k };
161 foreach my $v (@{ $data ->{ $k }}) {
165 $raw .= " $k = $data ->{ $k } \n " ;
169 foreach my $k ( sort keys %$data ) {
170 next if $k !~ m/^pve\./ ;
171 $done_hash ->{ $k } = 1 ;
172 $raw .= " $k = $data ->{ $k } \n " ;
175 foreach my $k ( sort keys %$data ) {
176 next if $k !~ m/^net\d+$/ ;
177 $done_hash ->{ $k } = 1 ;
178 my $net = $data ->{ $k };
179 $raw .= "lxc.network.type = $net ->{type} \n " ;
180 foreach my $subkey ( sort keys %$net ) {
181 next if $subkey eq 'type' ;
182 if ( $valid_lxc_network_keys ->{ $subkey }) {
183 $raw .= "lxc.network. $subkey = $net ->{ $subkey } \n " ;
184 } elsif ( $valid_pve_network_keys ->{ $subkey }) {
185 $raw .= "pve.network. $subkey = $net ->{ $subkey } \n " ;
187 die "found invalid network key ' $subkey '" ;
192 foreach my $k ( sort keys %$data ) {
193 next if $done_hash ->{ $k };
194 die "found un-written value in config - implement this!" ;
200 sub parse_lxc_option
{
201 my ( $name, $value ) = @_ ;
203 my $parser = $valid_lxc_keys ->{ $name };
205 die "inavlid key ' $name ' \n " if ! defined ( $parser );
207 if ( $parser eq '1' ) {
209 } elsif ( ref ( $parser )) {
210 my $res = & $parser ( $name, $value );
211 return $res if defined ( $res );
214 return $value if $value =~ m/^$parser$/ ;
217 die "unable to parse value ' $value ' for option ' $name ' \n " ;
220 sub parse_lxc_config
{
221 my ( $filename, $raw ) = @_ ;
223 return undef if ! defined ( $raw );
226 digest
=> Digest
:: SHA
:: sha1_hex
( $raw ),
229 $filename =~ m
| /lxc/ ( \d
+)/ config
$|
230 || die "got strange filename ' $filename '" ;
234 my $network_counter = 0 ;
235 my $network_list = [];
236 my $host_ifnames = {};
238 my $find_next_hostif_name = sub {
239 for ( my $i = 0 ; $i < 10 ; $i++ ) {
240 my $name = "veth${vmid}. $i " ;
241 if (! $host_ifnames ->{ $name }) {
242 $host_ifnames ->{ $name } = 1 ;
247 die "unable to find free host_ifname" ; # should not happen
250 my $push_network = sub {
253 push @{ $network_list }, $netconf ;
255 if ( my $netname = $netconf ->{ 'veth.pair' }) {
256 if ( $netname =~ m/^veth(\d+).(\d)$/ ) {
257 die "wrong vmid for network interface pair \n " if $1 != $vmid ;
258 my $host_ifnames ->{ $netname } = 1 ;
260 die "wrong network interface pair \n " ;
267 while ( $raw && $raw =~ s/^(.*?)(\n|$)// ) {
270 next if $line =~ m/^\#/ ;
271 next if $line =~ m/^\s*$/ ;
273 if ( $line =~ m/^lxc\.network\.(\S+)\s*=\s*(\S+)\s*$/ ) {
274 my ( $subkey, $value ) = ( $1, $2 );
275 if ( $subkey eq 'type' ) {
276 & $push_network ( $network );
277 $network = { type
=> $value };
278 } elsif ( $valid_lxc_network_keys ->{ $subkey }) {
279 $network ->{ $subkey } = $value ;
281 die "unable to parse config line: $line\n " ;
285 if ( $line =~ m/^pve\.network\.(\S+)\s*=\s*(\S+)\s*$/ ) {
286 my ( $subkey, $value ) = ( $1, $2 );
287 if ( $valid_pve_network_keys ->{ $subkey }) {
288 $network ->{ $subkey } = $value ;
290 die "unable to parse config line: $line\n " ;
294 if ( $line =~ m/^(pve.comment)\s*=\s*(\S.*)\s*$/ ) {
295 my ( $name, $value ) = ( $1, $2 );
296 $data ->{ $name } = $value ;
299 if ( $line =~ m/^((?:pve|lxc)\.\S+)\s*=\s*(\S.*)\s*$/ ) {
300 my ( $name, $value ) = ( $1, $2 );
302 if ( $lxc_array_configs ->{ $name }) {
303 $data ->{ $name } = [] if ! defined ( $data ->{ $name });
304 push @{ $data ->{ $name }}, parse_lxc_option
( $name, $value );
306 die "multiple definitions for $name\n " if defined ( $data ->{ $name });
307 $data ->{ $name } = parse_lxc_option
( $name, $value );
313 die "unable to parse config line: $line\n " ;
316 & $push_network ( $network );
318 foreach my $net (@{ $network_list }) {
319 $net ->{ 'veth.pair' } = & $find_next_hostif_name () if ! $net ->{ 'veth.pair' };
320 $net ->{ hwaddr
} = PVE
:: Tools
:: random_ether_addr
() if ! $net ->{ hwaddr
};
321 die "unsupported network type ' $net ->{type}' \n " if $net ->{ type
} ne 'veth' ;
323 if ( $net ->{ 'veth.pair' } =~ m/^veth\d+.(\d+)$/ ) {
324 $data ->{ "net $1 " } = $net ;
332 my $vmlist = PVE
:: Cluster
:: get_vmlist
();
334 return $res if ! $vmlist || ! $vmlist ->{ ids
};
335 my $ids = $vmlist ->{ ids
};
337 foreach my $vmid ( keys %$ids ) {
338 next if ! $vmid ; # skip CT0
339 my $d = $ids ->{ $vmid };
340 next if ! $d ->{ node
} || $d ->{ node
} ne $nodename ;
341 next if ! $d ->{ type
} || $d ->{ type
} ne 'lxc' ;
342 $res ->{ $vmid }->{ type
} = 'lxc' ;
347 sub cfs_config_path
{
348 my ( $vmid, $node ) = @_ ;
350 $node = $nodename if ! $node ;
351 return "nodes/ $node/lxc/$vmid/config " ;
355 my ( $vmid, $node ) = @_ ;
357 my $cfspath = cfs_config_path
( $vmid, $node );
358 return "/etc/pve/ $cfspath " ;
364 my $cfspath = cfs_config_path
( $vmid );
366 my $conf = PVE
:: Cluster
:: cfs_read_file
( $cfspath );
367 die "container $vmid does not exists \n " if ! defined ( $conf );
373 my ( $vmid, $conf ) = @_ ;
375 my $dir = "/etc/pve/nodes/ $nodename/lxc " ;
379 mkdir ( $dir ) || die "unable to create container configuration directory - $!\n " ;
381 write_config
( $vmid, $conf );
387 my $dir = "/etc/pve/nodes/ $nodename/lxc/$vmid " ;
388 File
:: Path
:: rmtree
( $dir );
392 my ( $vmid, $conf ) = @_ ;
394 my $cfspath = cfs_config_path
( $vmid );
396 PVE
:: Cluster
:: cfs_write_file
( $cfspath, $conf );
400 sub write_temp_config
{
401 my ( $vmid, $conf ) = @_ ;
404 my $filename = "/tmp/temp-lxc-conf- $vmid - $$ - $tempcounter .conf" ;
406 my $raw = write_lxc_config
( $filename, $conf );
408 PVE
:: Tools
:: file_set_contents
( $filename, $raw );
414 my ( $vmid, $timeout, $code, @param ) = @_ ;
416 my $lockdir = "/run/lock/lxc" ;
417 my $lockfile = " $lockdir/pve -config-{ $vmid }.lock" ;
419 File
:: Path
:: make_path
( $lockdir );
421 my $res = PVE
:: Tools
:: lock_file
( $lockfile, $timeout, $code, @param );
432 description
=> "Specifies whether a VM will be started during system bootup." ,
435 startup
=> get_standard_option
( 'pve-startup-order' ),
439 description
=> "The number of CPUs for this container (0 is unlimited)." ,
447 description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs. \n\n NOTE: You can disable fair-scheduler configuration by setting this to 0." ,
455 description
=> "Amount of RAM for the VM in MB." ,
462 description
=> "Amount of SWAP for the VM in MB." ,
469 description
=> "Amount of disk space for the VM in GB. A zero indicates no limits." ,
475 description
=> "Set a host name for the container." ,
482 description
=> "Container description. Only used on the configuration web interface." ,
487 description
=> "Sets DNS search domains for a container. Create will automatically use the setting from the host if you neither set searchdomain or nameserver." ,
492 description
=> "Sets DNS server IP address for a container. Create will automatically use the setting from the host if you neither set searchdomain or nameserver." ,
496 my $MAX_LXC_NETWORKS = 10 ;
497 for ( my $i = 0 ; $i < $MAX_LXC_NETWORKS ; $i++ ) {
498 $confdesc ->{ "net $i " } = {
500 type
=> 'string' , format
=> 'pve-lxc-network' ,
501 description
=> "Specifies network interfaces for the container." ,
508 return defined ( $confdesc ->{ $name });
511 # add JSON properties for create and set function
512 sub json_config_properties
{
515 foreach my $opt ( keys %$confdesc ) {
516 $prop ->{ $opt } = $confdesc ->{ $opt };
522 # container status helpers
524 sub list_active_containers
{
526 my $filename = "/proc/net/unix" ;
528 # similar test is used by lcxcontainers.c: list_active_containers
531 my $fh = IO
:: File-
> new ( $filename, "r" );
534 while ( defined ( my $line = < $fh >)) {
535 if ( $line =~ m/^[a-f0-9]+:\s\S+\s\S+\s\S+\s\S+\s\S+\s\d+\s(\S+)$/ ) {
537 if ( $path =~ m!^@/etc/pve/lxc/(\d+)/command$! ) {
548 # warning: this is slow
552 my $active_hash = list_active_containers
();
554 return 1 if defined ( $active_hash ->{ $vmid });
559 sub get_container_disk_usage
{
562 my $cmd = [ 'lxc-attach' , '-n' , $vmid, '--' , 'df' , '-P' , '-B' , '1' , '/' ];
572 if ( my ( $fsid, $total, $used, $avail ) = $line =~
573 m/^(\S+.*)\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+%\s.*$/ ) {
581 eval { PVE
:: Tools
:: run_command
( $cmd, timeout
=> 1 , outfunc
=> $parser ); };
590 my $list = $opt_vmid ?
{ $opt_vmid => { type
=> 'lxc' }} : config_list
();
592 my $active_hash = list_active_containers
();
594 foreach my $vmid ( keys %$list ) {
595 my $d = $list ->{ $vmid };
597 my $running = defined ( $active_hash ->{ $vmid });
599 $d ->{ status
} = $running ?
'running' : 'stopped' ;
601 my $cfspath = cfs_config_path
( $vmid );
602 my $conf = PVE
:: Cluster
:: cfs_read_file
( $cfspath ) || {};
604 $d ->{ name
} = $conf ->{ 'lxc.utsname' } || "CT $vmid " ;
605 $d ->{ name
} =~ s/[\s]//g ;
609 my $cfs_period_us = $conf ->{ 'lxc.cgroup.cpu.cfs_period_us' };
610 my $cfs_quota_us = $conf ->{ 'lxc.cgroup.cpu.cfs_quota_us' };
612 if ( $cfs_period_us && $cfs_quota_us ) {
613 $d ->{ cpus
} = int ( $cfs_quota_us/$cfs_period_us );
617 $d ->{ maxdisk
} = defined ( $conf ->{ 'pve.disksize' }) ?
618 int ( $conf ->{ 'pve.disksize' }* 1024 * 1024 )* 1024 : 1024 * 1024 * 1024 * 1024 * 1024 ;
620 if ( my $private = $conf ->{ 'lxc.rootfs' }) {
621 if ( $private =~ m!^/! ) {
622 my $res = PVE
:: Tools
:: df
( $private, 2 );
623 $d ->{ disk
} = $res ->{ used
};
624 $d ->{ maxdisk
} = $res ->{ total
};
626 if ( $private =~ m!^(?:loop|nbd):(?:\S+)$! ) {
627 my $res = get_container_disk_usage
( $vmid );
628 $d ->{ disk
} = $res ->{ used
};
629 $d ->{ maxdisk
} = $res ->{ total
};
636 $d ->{ maxmem
} = ( $conf ->{ 'lxc.cgroup.memory.limit_in_bytes' }|| 0 ) +
637 ( $conf ->{ 'lxc.cgroup.memory.memsw.limit_in_bytes' }|| 0 );
649 foreach my $vmid ( keys %$list ) {
650 my $d = $list ->{ $vmid };
651 next if $d ->{ status
} ne 'running' ;
653 $d ->{ uptime
} = 100 ; # fixme:
655 $d ->{ mem
} = read_cgroup_value
( 'memory' , $vmid, 'memory.usage_in_bytes' );
656 $d ->{ swap
} = read_cgroup_value
( 'memory' , $vmid, 'memory.memsw.usage_in_bytes' ) - $d ->{ mem
};
663 sub print_lxc_network
{
666 die "no network bridge defined \n " if ! $net ->{ bridge
};
668 my $res = "bridge= $net ->{bridge}" ;
670 foreach my $k ( qw(hwaddr mtu name ip gw ip6 gw6 firewall tag) ) {
671 next if ! defined ( $net ->{ $k });
672 $res .= ", $k = $net ->{ $k }" ;
678 sub parse_lxc_network
{
683 return $res if ! $data ;
685 foreach my $pv ( split ( /,/ , $data )) {
686 if ( $pv =~ m/^(bridge|hwaddr|mtu|name|ip|ip6|gw|gw6|firewall|tag)=(\S+)$/ ) {
693 $res ->{ type
} = 'veth' ;
694 $res ->{ hwaddr
} = PVE
:: Tools
:: random_ether_addr
() if ! $res ->{ mac
};
699 sub read_cgroup_value
{
700 my ( $group, $vmid, $name, $full ) = @_ ;
702 my $path = "/sys/fs/cgroup/ $group/lxc/$vmid/$name " ;
704 return PVE
:: Tools
:: file_get_contents
( $path ) if $full ;
706 return PVE
:: Tools
:: file_read_firstline
( $path );
709 sub find_lxc_console_pids
{
713 PVE
:: Tools
:: dir_glob_foreach
( '/proc' , '\d+' , sub {
716 my $cmdline = PVE
:: Tools
:: file_read_firstline
( "/proc/ $pid/cmdline " );
719 my @args = split ( /\0/ , $cmdline );
721 # serach for lxc-console -n <vmid>
722 return if scalar ( @args ) != 3 ;
723 return if $args [ 1 ] ne '-n' ;
724 return if $args [ 2 ] !~ m/^\d+$/ ;
725 return if $args [ 0 ] !~ m
|^( /usr/ bin
/) ?lxc-console
$|;
729 push @{ $res ->{ $vmid }}, $pid ;
735 my $ipv4_reverse_mask = [
771 # Note: we cannot use Net:IP, because that only allows strict
773 sub parse_ipv4_cidr
{
774 my ( $cidr, $noerr ) = @_ ;
776 if ( $cidr =~ m!^($IPV4RE)(?:/(\d+))$! && ( $2 > 7 ) && ( $2 < 32 )) {
777 return { address
=> $1, netmask
=> $ipv4_reverse_mask ->[ $2 ] };
780 return undef if $noerr ;
782 die "unable to parse ipv4 address/mask \n " ;
785 sub lxc_conf_to_pve
{
786 my ( $vmid, $lxc_conf ) = @_ ;
788 my $properties = json_config_properties
();
790 my $conf = { digest
=> $lxc_conf ->{ digest
} };
792 foreach my $k ( keys %$properties ) {
794 if ( $k eq 'description' ) {
795 if ( my $raw = $lxc_conf ->{ 'pve.comment' }) {
796 $conf ->{ $k } = PVE
:: Tools
:: decode_text
( $raw );
798 } elsif ( $k eq 'onboot' ) {
799 $conf ->{ $k } = $lxc_conf ->{ 'pve.onboot' } if $lxc_conf ->{ 'pve.onboot' };
800 } elsif ( $k eq 'startup' ) {
801 $conf ->{ $k } = $lxc_conf ->{ 'pve.startup' } if $lxc_conf ->{ 'pve.startup' };
802 } elsif ( $k eq 'hostname' ) {
803 $conf ->{ $k } = $lxc_conf ->{ 'lxc.utsname' } if $lxc_conf ->{ 'lxc.utsname' };
804 } elsif ( $k eq 'nameserver' ) {
805 $conf ->{ $k } = $lxc_conf ->{ 'pve.nameserver' } if $lxc_conf ->{ 'pve.nameserver' };
806 } elsif ( $k eq 'searchdomain' ) {
807 $conf ->{ $k } = $lxc_conf ->{ 'pve.searchdomain' } if $lxc_conf ->{ 'pve.searchdomain' };
808 } elsif ( $k eq 'memory' ) {
809 if ( my $value = $lxc_conf ->{ 'lxc.cgroup.memory.limit_in_bytes' }) {
810 $conf ->{ $k } = int ( $value / ( 1024 * 1024 ));
812 } elsif ( $k eq 'swap' ) {
813 if ( my $value = $lxc_conf ->{ 'lxc.cgroup.memory.memsw.limit_in_bytes' }) {
814 my $mem = $lxc_conf ->{ 'lxc.cgroup.memory.limit_in_bytes' } || 0 ;
815 $conf ->{ $k } = int (( $value - $mem ) / ( 1024 * 1024 ));
817 } elsif ( $k eq 'cpus' ) {
818 my $cfs_period_us = $lxc_conf ->{ 'lxc.cgroup.cpu.cfs_period_us' };
819 my $cfs_quota_us = $lxc_conf ->{ 'lxc.cgroup.cpu.cfs_quota_us' };
821 if ( $cfs_period_us && $cfs_quota_us ) {
822 $conf ->{ $k } = int ( $cfs_quota_us/$cfs_period_us );
826 } elsif ( $k eq 'cpuunits' ) {
827 $conf ->{ $k } = $lxc_conf ->{ 'lxc.cgroup.cpu.shares' } || 1024 ;
828 } elsif ( $k eq 'disk' ) {
829 $conf ->{ $k } = defined ( $lxc_conf ->{ 'pve.disksize' }) ?
830 $lxc_conf ->{ 'pve.disksize' } : 0 ;
831 } elsif ( $k =~ m/^net\d$/ ) {
832 my $net = $lxc_conf ->{ $k };
834 $conf ->{ $k } = print_lxc_network
( $net );
841 # verify and cleanup nameserver list (replace \0 with ' ')
842 sub verify_nameserver_list
{
843 my ( $nameserver_list ) = @_ ;
846 foreach my $server ( PVE
:: Tools
:: split_list
( $nameserver_list )) {
847 PVE
:: JSONSchema
:: pve_verify_ip
( $server );
851 return join ( ' ' , @list );
854 sub verify_searchdomain_list
{
855 my ( $searchdomain_list ) = @_ ;
858 foreach my $server ( PVE
:: Tools
:: split_list
( $searchdomain_list )) {
859 # todo: should we add checks for valid dns domains?
863 return join ( ' ' , @list );
866 sub update_lxc_config
{
867 my ( $vmid, $conf, $running, $param, $delete ) = @_ ;
870 die "unable to modify config while container is running \n " if $running ;
872 if ( defined ( $delete )) {
873 foreach my $opt ( @$delete ) {
874 if ( $opt eq 'hostname' || $opt eq 'memory' ) {
875 die "unable to delete required option ' $opt ' \n " ;
876 } elsif ( $opt eq 'swap' ) {
877 delete $conf ->{ 'lxc.cgroup.memory.memsw.limit_in_bytes' };
878 } elsif ( $opt eq 'description' ) {
879 delete $conf ->{ 'pve.comment' };
880 } elsif ( $opt eq 'onboot' ) {
881 delete $conf ->{ 'pve.onboot' };
882 } elsif ( $opt eq 'startup' ) {
883 delete $conf ->{ 'pve.startup' };
884 } elsif ( $opt eq 'nameserver' ) {
885 delete $conf ->{ 'pve.nameserver' };
886 } elsif ( $opt eq 'searchdomain' ) {
887 delete $conf ->{ 'pve.searchdomain' };
888 } elsif ( $opt =~ m/^net\d$/ ) {
889 delete $conf ->{ $opt };
896 foreach my $opt ( keys %$param ) {
897 my $value = $param ->{ $opt };
898 if ( $opt eq 'hostname' ) {
899 $conf ->{ 'lxc.utsname' } = $value ;
900 } elsif ( $opt eq 'onboot' ) {
901 $conf ->{ 'pve.onboot' } = $value ?
1 : 0 ;
902 } elsif ( $opt eq 'startup' ) {
903 $conf ->{ 'pve.startup' } = $value ;
904 } elsif ( $opt eq 'nameserver' ) {
905 my $list = verify_nameserver_list
( $value );
906 $conf ->{ 'pve.nameserver' } = $list ;
907 } elsif ( $opt eq 'searchdomain' ) {
908 my $list = verify_searchdomain_list
( $value );
909 $conf ->{ 'pve.searchdomain' } = $list ;
910 } elsif ( $opt eq 'memory' ) {
911 $conf ->{ 'lxc.cgroup.memory.limit_in_bytes' } = $value*1024*1024 ;
912 } elsif ( $opt eq 'swap' ) {
913 my $mem = $conf ->{ 'lxc.cgroup.memory.limit_in_bytes' };
914 $mem = $param ->{ memory
}* 1024 * 1024 if $param ->{ memory
};
915 $conf ->{ 'lxc.cgroup.memory.memsw.limit_in_bytes' } = $mem + $value*1024*1024 ;
916 } elsif ( $opt eq 'cpus' ) {
918 my $cfs_period_us = 100000 ;
919 $conf ->{ 'lxc.cgroup.cpu.cfs_period_us' } = $cfs_period_us ;
920 $conf ->{ 'lxc.cgroup.cpu.cfs_quota_us' } = $cfs_period_us*$value ;
922 delete $conf ->{ 'lxc.cgroup.cpu.cfs_period_us' };
923 delete $conf ->{ 'lxc.cgroup.cpu.cfs_quota_us' };
925 } elsif ( $opt eq 'cpuunits' ) {
926 $conf ->{ 'lxc.cgroup.cpu.shares' } = $value ;
927 } elsif ( $opt eq 'description' ) {
928 $conf ->{ 'pve.comment' } = PVE
:: Tools
:: encode_text
( $value );
929 } elsif ( $opt eq 'disk' ) {
930 $conf ->{ 'pve.disksize' } = $value ;
931 } elsif ( $opt =~ m/^net(\d+)$/ ) {
933 my $net = PVE
:: LXC
:: parse_lxc_network
( $value );
934 $net ->{ 'veth.pair' } = "veth${vmid}. $netid " ;
935 $conf ->{ $opt } = $net ;
942 sub get_primary_ips
{
945 # return data from net0
947 my $net = $conf ->{ net0
};
948 return undef if ! $net ;
950 my $ipv4 = $net ->{ ip
};
951 $ipv4 =~ s!/\d+$!! if $ipv4 ;
952 my $ipv6 = $net ->{ ip
};
953 $ipv6 =~ s!/\d+$!! if $ipv6 ;
955 return ( $ipv4, $ipv6 );