]>
git.proxmox.com Git - pve-storage.git/blob - PVE/API2/Disks/Directory.pm
1 package PVE
::API2
::Disks
::Directory
;
7 use PVE
::JSONSchema
qw(get_standard_option);
9 use PVE
::RPCEnvironment
;
11 use PVE
::Tools
qw(run_command trim file_set_contents file_get_contents dir_glob_foreach lock_file);
13 use PVE
::API2
::Storage
::Config
;
15 use base
qw(PVE::RESTHandler);
17 my $SGDISK = '/sbin/sgdisk';
18 my $MKFS = '/sbin/mkfs';
19 my $BLKID = '/sbin/blkid';
24 my $content = file_get_contents
($filename);
25 my @lines = split /\n/, $content;
30 foreach my $line (@lines) {
32 if ($line =~ m/^\[([^\]]+)\]/) {
34 if (!defined($result->{$section})) {
35 $result->{$section} = {};
37 } elsif ($line =~ m/^(.*?)=(.*)$/) {
38 my ($key, $val) = ($1, $2);
40 warn "key value pair found without section, skipping\n";
44 if ($result->{$section}->{$key}) {
45 # make duplicate properties to arrays to keep the order
46 my $prop = $result->{$section}->{$key};
47 if (ref($prop) eq 'ARRAY') {
50 $result->{$section}->{$key} = [$prop, $val];
53 $result->{$section}->{$key} = $val;
56 # ignore everything else
63 my ($ini, $filename) = @_;
67 foreach my $sname (sort keys %$ini) {
68 my $section = $ini->{$sname};
70 $content .= "[$sname]\n";
72 foreach my $pname (sort keys %$section) {
73 my $prop = $section->{$pname};
76 $content .= "$pname=$prop\n";
77 } elsif (ref($prop) eq 'ARRAY') {
78 foreach my $val (@$prop) {
79 $content .= "$pname=$val\n";
82 die "invalid property '$pname'\n";
88 file_set_contents
($filename, $content);
91 __PACKAGE__-
>register_method ({
98 check
=> ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any
=> 1],
100 description
=> "PVE Managed Directory storages.",
102 additionalProperties
=> 0,
104 node
=> get_standard_option
('pve-node'),
114 description
=> 'The path of the mount unit.',
118 description
=> 'The mount path.',
122 description
=> 'The mounted device.',
126 description
=> 'The filesystem type.',
130 description
=> 'The mount options.',
140 dir_glob_foreach
('/etc/systemd/system', '^mnt-pve-(.+)\.mount$', sub {
141 my ($filename, $storid) = @_;
142 $storid = PVE
::Systemd
::unescape_unit
($storid);
144 my $unitfile = "/etc/systemd/system/$filename";
145 my $unit = $read_ini->($unitfile);
148 unitfile
=> $unitfile,
149 path
=> "/mnt/pve/$storid",
150 device
=> $unit->{'Mount'}->{'What'},
151 type
=> $unit->{'Mount'}->{'Type'},
152 options
=> $unit->{'Mount'}->{'Options'},
159 __PACKAGE__-
>register_method ({
166 check
=> ['perm', '/', ['Sys.Modify', 'Datastore.Allocate']],
168 description
=> "Create a Filesystem on an unused disk. Will be mounted under '/mnt/pve/NAME'.",
170 additionalProperties
=> 0,
172 node
=> get_standard_option
('pve-node'),
173 name
=> get_standard_option
('pve-storage-id'),
176 description
=> 'The block device you want to create the filesystem on.',
179 description
=> "Configure storage using the directory.",
185 description
=> "The desired filesystem.",
187 enum
=> ['ext4', 'xfs'],
193 returns
=> { type
=> 'string' },
197 my $rpcenv = PVE
::RPCEnvironment
::get
();
198 my $user = $rpcenv->get_user();
200 my $name = $param->{name
};
201 my $dev = $param->{device
};
202 my $node = $param->{node
};
203 my $type = $param->{filesystem
} // 'ext4';
205 $dev = PVE
::Diskmanage
::verify_blockdev_path
($dev);
206 PVE
::Diskmanage
::assert_disk_unused
($dev);
207 PVE
::Storage
::assert_sid_unused
($name) if $param->{add_storage
};
210 my $path = "/mnt/pve/$name";
211 my $mountunitname = PVE
::Systemd
::escape_unit
($path, 1) . ".mount";
212 my $mountunitpath = "/etc/systemd/system/$mountunitname";
214 PVE
::Diskmanage
::locked_disk_action
(sub {
215 PVE
::Diskmanage
::assert_disk_unused
($dev);
218 my $cmd = [$SGDISK, '-n1', '-t1:8300', $dev];
219 print "# ", join(' ', @$cmd), "\n";
222 my ($devname) = $dev =~ m
|^/dev/(.*)$|;
224 dir_glob_foreach
("/sys/block/$devname", qr
/\Q
$devname\E.+/, sub {
225 my ($partition) = @_;
230 $cmd = [$MKFS, '-t', $type, $part];
231 print "# ", join(' ', @$cmd), "\n";
234 # create systemd mount unit and enable & start it
237 'Description' => "Mount storage '$name' under /mnt/pve",
240 'WantedBy' => 'multi-user.target',
247 $cmd = [$BLKID, $part, '-o', 'export'];
248 print "# ", join(' ', @$cmd), "\n";
249 run_command
($cmd, outfunc
=> sub {
252 if ($line =~ m/^UUID=(.*)$/) {
254 $uuid_path = "/dev/disk/by-uuid/$uuid";
258 die "could not get UUID of device '$part'\n" if !$uuid;
261 'What' => $uuid_path,
264 'Options' => 'defaults',
267 $write_ini->($ini, $mountunitpath);
269 # FIXME: Remove once we depend on systemd >= v249.
270 # Work around udev bug https://github.com/systemd/systemd/issues/18525 to ensure the
271 # udev database is updated and the $uuid_path symlink is actually created!
272 eval { run_command
(['udevadm', 'trigger', $part]); };
275 run_command
(['systemctl', 'daemon-reload']);
276 run_command
(['systemctl', 'enable', $mountunitname]);
277 run_command
(['systemctl', 'start', $mountunitname]);
279 if ($param->{add_storage
}) {
280 my $storage_params = {
283 content
=> 'rootdir,images,iso,backup,vztmpl,snippets',
289 PVE
::API2
::Storage
::Config-
>create($storage_params);
294 return $rpcenv->fork_worker('dircreate', $name, $user, $worker);