]>
Commit | Line | Data |
---|---|---|
5b4657d0 DM |
1 | package PVE::LXCCreate; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use File::Basename; | |
6 | use File::Path; | |
7 | use Data::Dumper; | |
8 | ||
9 | use PVE::Storage; | |
10 | use PVE::LXC; | |
11 | use PVE::LXCSetup; | |
12 | ||
13 | sub restore_archive { | |
14 | my ($archive, $rootdir, $conf) = @_; | |
15 | ||
16 | # we always use the same mapping: 'b:0:100000:65536' | |
17 | my $userns_cmd; | |
18 | ||
19 | if ($conf->{'lxc.id_map'}) { | |
20 | $userns_cmd = ['lxc-usernsexec', '-m', 'b:0:100000:65536', '--']; | |
21 | } else { | |
22 | $userns_cmd = []; | |
23 | } | |
24 | ||
25 | my $cmd; | |
26 | ||
27 | if ($conf->{'lxc.id_map'}) { | |
28 | PVE::Tools::run_command(['chown', '-R', '100000:100000', $rootdir]); | |
29 | } | |
30 | ||
31 | $cmd = [@$userns_cmd, 'tar', 'xpf', $archive, '--numeric-owner', '--totals', | |
32 | '--sparse', '-C', $rootdir]; | |
33 | ||
34 | push @$cmd, '--anchored'; | |
35 | push @$cmd, '--exclude' , './dev/*'; | |
36 | ||
37 | print "extracting archive '$archive'\n"; | |
38 | PVE::Tools::run_command($cmd); | |
39 | ||
40 | # is this really required? what for? | |
41 | #$cmd = [@$userns_cmd, 'mkdir', '-p', "$rootdir/dev/pts"]; | |
42 | #PVE::Tools::run_command($cmd); | |
43 | ||
44 | # template/OS specific configuration | |
45 | $conf->{'lxc.arch'} = 'i386'; #fixme: || x86_64 | |
46 | } | |
47 | ||
48 | sub restore_and_configure { | |
49 | my ($vmid, $archive, $rootdir, $conf, $password) = @_; | |
50 | ||
51 | restore_archive($archive, $rootdir, $conf); | |
52 | ||
53 | PVE::LXC::write_config($vmid, $conf); | |
54 | ||
55 | my $lxc_setup = PVE::LXCSetup->new($conf, $rootdir); # detect OS | |
56 | ||
57 | PVE::LXC::write_config($vmid, $conf); # safe config (after OS detection) | |
58 | ||
59 | $lxc_setup->post_create_hook($password); | |
60 | } | |
61 | ||
62 | # directly use a storage directory | |
63 | sub create_rootfs_dir { | |
10fc3ba5 | 64 | my ($cleanup, $storage_conf, $storage, $vmid, $conf, $archive, $password) = @_; |
5b4657d0 | 65 | |
10fc3ba5 | 66 | # note: there is no size limit |
5b4657d0 DM |
67 | |
68 | my $private = PVE::Storage::get_private_dir($storage_conf, $storage, $vmid); | |
69 | mkdir($private) || die "unable to create container private dir '$private' - $!\n"; | |
70 | ||
71 | push @{$cleanup->{files}}, $private; | |
72 | $conf->{'lxc.rootfs'} = $private; | |
73 | ||
74 | restore_and_configure($vmid, $archive, $private, $conf, $password); | |
75 | } | |
76 | ||
77 | # create a raw file, then loop mount | |
78 | sub create_rootfs_dir_loop { | |
79 | my ($cleanup, $storage_conf, $storage, $size, $vmid, $conf, $archive, $password) = @_; | |
80 | ||
81 | my $volid = PVE::Storage::vdisk_alloc($storage_conf, $storage, $vmid, 'raw', "vm-$vmid-rootfs.raw", $size); | |
82 | ||
83 | push @{$cleanup->{volids}}, $volid; | |
84 | ||
85 | my $image_path = PVE::Storage::path($storage_conf, $volid); | |
86 | $conf->{'lxc.rootfs'} = "loop:${image_path}"; | |
87 | ||
88 | my $cmd = ['mkfs.ext4', $image_path]; | |
89 | PVE::Tools::run_command($cmd); | |
90 | ||
91 | print "allocated image: $image_path\n"; | |
92 | ||
93 | my $mountpoint; | |
94 | ||
95 | my $loopdev; | |
96 | eval { | |
97 | my $parser = sub { | |
98 | my $line = shift; | |
99 | $loopdev = $line if $line =~m|^/dev/loop\d+$|; | |
100 | }; | |
101 | PVE::Tools::run_command(['losetup', '--find', '--show', $image_path], outfunc => $parser); | |
102 | ||
103 | my $tmp = "/var/lib/lxc/$vmid/rootfs"; | |
104 | File::Path::mkpath($tmp); | |
105 | PVE::Tools::run_command(['mount', '-t', 'ext4', $loopdev, $tmp]); | |
106 | $mountpoint = $tmp; | |
107 | ||
108 | restore_and_configure($vmid, $archive, $mountpoint, $conf, $password); | |
109 | }; | |
110 | if (my $err = $@) { | |
111 | if ($mountpoint) { | |
112 | eval { PVE::Tools::run_command(['umount', '-d', $mountpoint]) }; | |
113 | warn $@ if $@; | |
114 | } else { | |
115 | eval { PVE::Tools::run_command(['losetup', '-d', $loopdev]) if $loopdev; }; | |
116 | warn $@ if $@; | |
117 | } | |
118 | die $err; | |
119 | } | |
120 | ||
121 | PVE::Tools::run_command(['umount', '-l', '-d', $mountpoint]); | |
122 | } | |
123 | ||
124 | sub create_rootfs { | |
125 | my ($storage_conf, $storage, $size, $vmid, $conf, $archive, $password) = @_; | |
126 | ||
127 | PVE::LXC::create_config($vmid, $conf); | |
128 | ||
129 | my $cleanup = { files => [], volids => [] }; | |
130 | ||
131 | eval { | |
132 | my $scfg = PVE::Storage::storage_config($storage_conf, $storage); | |
133 | if ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs') { | |
10fc3ba5 | 134 | if ($size > 0) { |
5b4657d0 DM |
135 | create_rootfs_dir_loop($cleanup, $storage_conf, $storage, $size, $vmid, $conf, $archive, $password); |
136 | } else { | |
10fc3ba5 | 137 | create_rootfs_dir($cleanup, $storage_conf, $storage, $vmid, $conf, $archive, $password); |
5b4657d0 DM |
138 | } |
139 | } else { | |
140 | die "unable to create containers on storage type '$scfg->{type}'\n"; | |
141 | } | |
142 | }; | |
143 | if (my $err = $@) { | |
144 | # cleanup | |
145 | File::Path::rmtree($cleanup->{files}); | |
146 | foreach my $volid (@{$cleanup->{volids}}) { | |
147 | eval { PVE::Storage::vdisk_free($storage_conf, $volid); }; | |
148 | warn $@ if $@; | |
149 | } | |
150 | ||
151 | PVE::LXC::destroy_config($vmid); | |
152 | ||
153 | die $err; | |
154 | } | |
155 | } | |
156 | ||
157 | 1; |