]>
git.proxmox.com Git - pve-container.git/blob - src/PVE/LXC.pm
9 use PVE
:: Cluster
qw(cfs_register_file cfs_read_file) ;
15 cfs_register_file
( '/lxc/' , \
& parse_lxc_config
, \
& write_lxc_config
);
17 my $nodename = PVE
:: INotify
:: nodename
();
19 my $valid_lxc_keys = {
26 'lxc.cgroup.memory.limit_in_bytes' => 1 ,
32 my $valid_network_keys = {
37 name
=> 1 , # ifname inside container
38 'veth.pair' => 1 , # ifname at host (eth${vmid}.X)
46 my $lxc_array_configs = {
52 sub write_lxc_config
{
53 my ( $filename, $data ) = @_ ;
57 return $raw if ! $data ;
59 my $done_hash = { digest
=> 1 };
61 foreach my $k ( sort keys %$data ) {
62 next if $k !~ m/^lxc\./ ;
64 $raw .= " $k = $data ->{ $k } \n " ;
67 foreach my $k ( sort keys %$data ) {
68 next if $k !~ m/^net\d+$/ ;
70 my $net = $data ->{ $k };
71 $raw .= "lxc.network.type = $net ->{type} \n " ;
72 foreach my $subkey ( sort keys %$net ) {
73 next if $subkey eq 'type' ;
74 $raw .= "lxc.network. $subkey = $net ->{ $subkey } \n " ;
78 foreach my $k ( sort keys %$data ) {
79 next if $done_hash ->{ $k };
80 die "found un-written value in config - implement this!" ;
86 sub parse_lxc_config
{
87 my ( $filename, $raw ) = @_ ;
89 return undef if ! defined ( $raw );
92 digest
=> Digest
:: SHA
:: sha1_hex
( $raw ),
95 $filename =~ m
| /lxc/ ( \d
+)/ config
$|
96 || die "got strange filename ' $filename '" ;
100 my $network_counter = 0 ;
101 my $network_list = [];
102 my $host_ifnames = {};
104 my $find_next_hostif_name = sub {
105 for ( my $i = 0 ; $i < 10 ; $i++ ) {
106 my $name = "veth${vmid}. $i " ;
107 if (! $host_ifnames ->{ $name }) {
108 $host_ifnames ->{ $name } = 1 ;
113 die "unable to find free host_ifname" ; # should not happen
116 my $push_network = sub {
119 push @{ $network_list }, $netconf ;
121 if ( my $netname = $netconf ->{ 'veth.pair' }) {
122 if ( $netname =~ m/^veth(\d+).(\d)$/ ) {
123 die "wrong vmid for network interface pair \n " if $1 != $vmid ;
124 my $host_ifnames ->{ $netname } = 1 ;
126 die "wrong network interface pair \n " ;
133 while ( $raw && $raw =~ s/^(.*?)(\n|$)// ) {
136 next if $line =~ m/^\#/ ;
137 next if $line =~ m/^\s*$/ ;
139 if ( $line =~ m/^lxc\.network\.(\S+)\s*=\s*(\S+)\s*$/ ) {
140 my ( $subkey, $value ) = ( $1, $2 );
141 if ( $subkey eq 'type' ) {
142 & $push_network ( $network );
143 $network = { type
=> $value };
144 } elsif ( $valid_network_keys ->{ $subkey }) {
145 $network ->{ $subkey } = $value ;
147 die "unable to parse config line: $line\n " ;
152 if ( $line =~ m/^(pve.comment)\s*=\s*(\S.*)\s*$/ ) {
153 my ( $name, $value ) = ( $1, $2 );
154 $data ->{ $name } = $value ;
157 if ( $line =~ m/^((?:pve|lxc)\.\S+)\s*=\s*(\S+)\s*$/ ) {
158 my ( $name, $value ) = ( $1, $2 );
160 die "inavlid key ' $name ' \n " if ! $valid_lxc_keys ->{ $name };
162 die "multiple definitions for $name\n " if defined ( $data ->{ $name });
164 $data ->{ $name } = $value ;
168 die "unable to parse config line: $line\n " ;
171 & $push_network ( $network );
173 foreach my $net (@{ $network_list }) {
174 $net ->{ 'veth.pair' } = & $find_next_hostif_name () if ! $net ->{ 'veth.pair' };
175 $net ->{ hwaddr
} = PVE
:: Tools
:: random_ether_addr
() if ! $net ->{ hwaddr
};
176 die "unsupported network type ' $net ->{type}' \n " if $net ->{ type
} ne 'veth' ;
178 if ( $net ->{ 'veth.pair' } =~ m/^veth\d+.(\d+)$/ ) {
179 $data ->{ "net $1 " } = $net ;
187 my $vmlist = PVE
:: Cluster
:: get_vmlist
();
189 return $res if ! $vmlist || ! $vmlist ->{ ids
};
190 my $ids = $vmlist ->{ ids
};
192 foreach my $vmid ( keys %$ids ) {
193 next if ! $vmid ; # skip CT0
194 my $d = $ids ->{ $vmid };
195 next if ! $d ->{ node
} || $d ->{ node
} ne $nodename ;
196 next if ! $d ->{ type
} || $d ->{ type
} ne 'lxc' ;
197 $res ->{ $vmid }->{ type
} = 'lxc' ;
202 sub cfs_config_path
{
203 my ( $vmid, $node ) = @_ ;
205 $node = $nodename if ! $node ;
206 return "nodes/ $node/lxc/$vmid/config " ;
210 my ( $vmid, $node ) = @_ ;
212 my $cfspath = cfs_config_path
( $vmid, $node );
213 return "/etc/pve/ $cfspath " ;
219 my $cfspath = cfs_config_path
( $vmid );
221 my $conf = PVE
:: Cluster
:: cfs_read_file
( $cfspath );
222 die "container $vmid does not exists \n " if ! defined ( $conf );
228 my ( $vmid, $conf ) = @_ ;
230 my $cfspath = cfs_config_path
( $vmid );
232 PVE
:: Cluster
:: cfs_write_file
( $cfspath, $conf );
236 sub write_temp_config
{
237 my ( $vmid, $conf ) = @_ ;
240 my $filename = "/tmp/temp-lxc-conf- $vmid - $$ - $tempcounter .conf" ;
242 my $raw = write_lxc_config
( $filename, $conf );
244 PVE
:: Tools
:: file_set_contents
( $filename, $raw );
250 my ( $vmid, $timeout, $code, @param ) = @_ ;
252 my $lockdir = "/run/lock/lxc" ;
253 my $lockfile = " $lockdir/pve -config-{ $vmid }.lock" ;
255 File
:: Path
:: make_path
( $lockdir );
257 my $res = PVE
:: Tools
:: lock_file
( $lockfile, $timeout, $code, @param );
268 description
=> "Specifies whether a VM will be started during system bootup." ,
274 description
=> "The number of CPUs for this container." ,
281 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." ,
289 description
=> "Amount of RAM for the VM in MB." ,
296 description
=> "Amount of SWAP for the VM in MB." ,
303 description
=> "Amount of disk space for the VM in GB. A zero indicates no limits." ,
309 description
=> "Set a host name for the container." ,
316 description
=> "Container description. Only used on the configuration web interface." ,
321 description
=> "Sets DNS search domains for a container. Create will automatically use the setting from the host if you neither set searchdomain or nameserver." ,
326 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." ,
330 type
=> 'string' , format
=> 'pve-lxc-network' ,
331 description
=> "Specifies network interfaces for the container." ,
335 # add JSON properties for create and set function
336 sub json_config_properties
{
339 foreach my $opt ( keys %$confdesc ) {
340 $prop ->{ $opt } = $confdesc ->{ $opt };
350 my $list = $opt_vmid ?
{ $opt_vmid => { type
=> 'lxc' }} : config_list
();
352 foreach my $vmid ( keys %$list ) {
353 next if $opt_vmid && ( $vmid ne $opt_vmid );
355 my $d = $list ->{ $vmid };
356 $d ->{ status
} = 'stopped' ;
358 my $cfspath = cfs_config_path
( $vmid );
359 if ( my $conf = PVE
:: Cluster
:: cfs_read_file
( $cfspath )) {
361 $d ->{ name
} = $conf ->{ 'lxc.utsname' } || "CT $vmid " ;
362 $d ->{ name
} =~ s/[\s]//g ;
373 my $res = "pair= $net ->{pair}" ;
375 foreach my $k ( qw(link hwaddr mtu name ipv4 ipv4.gateway ipv6 ipv6.gateway) ) {
376 next if ! defined ( $net ->{ $k });
377 $res .= ", $k = $net ->{ $k }" ;