]>
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);
8 use PVE
::API2
::Storage
::Config
;
9 use PVE
::Tools
qw(run_command trim file_set_contents file_get_contents dir_glob_foreach lock_file);
11 use PVE
::RPCEnvironment
;
14 use base
qw(PVE::RESTHandler);
16 my $SGDISK = '/sbin/sgdisk';
17 my $MKFS = '/sbin/mkfs';
18 my $BLKID = '/sbin/blkid';
23 my $content = file_get_contents
($filename);
24 my @lines = split /\n/, $content;
29 foreach my $line (@lines) {
31 if ($line =~ m/^\[([^\]]+)\]/) {
33 if (!defined($result->{$section})) {
34 $result->{$section} = {};
36 } elsif ($line =~ m/^(.*?)=(.*)$/) {
37 my ($key, $val) = ($1, $2);
39 warn "key value pair found without section, skipping\n";
43 if ($result->{$section}->{$key}) {
44 # make duplicate properties to arrays to keep the order
45 my $prop = $result->{$section}->{$key};
46 if (ref($prop) eq 'ARRAY') {
49 $result->{$section}->{$key} = [$prop, $val];
52 $result->{$section}->{$key} = $val;
55 # ignore everything else
62 my ($ini, $filename) = @_;
66 foreach my $sname (sort keys %$ini) {
67 my $section = $ini->{$sname};
69 $content .= "[$sname]\n";
71 foreach my $pname (sort keys %$section) {
72 my $prop = $section->{$pname};
75 $content .= "$pname=$prop\n";
76 } elsif (ref($prop) eq 'ARRAY') {
77 foreach my $val (@$prop) {
78 $content .= "$pname=$val\n";
81 die "invalid property '$pname'\n";
87 file_set_contents
($filename, $content);
93 # NOTE: this is not complete, but enough for our needs. normally all
94 # characters which are not alpha-numerical, '.' or '_' would need escaping
100 sub systemd_unescape
{
103 $val =~ s/\\x([a-fA-F0-9]{2})/chr(hex($1))/eg;
108 __PACKAGE__-
>register_method ({
115 check
=> ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any
=> 1],
117 description
=> "PVE Managed Directory storages.",
119 additionalProperties
=> 0,
121 node
=> get_standard_option
('pve-node'),
131 description
=> 'The path of the mount unit.',
135 description
=> 'The mount path.',
139 description
=> 'The mounted device.',
143 description
=> 'The filesystem type.',
147 description
=> 'The mount options.',
157 dir_glob_foreach
('/etc/systemd/system', '^mnt-pve-(.+)\.mount$', sub {
158 my ($filename, $storid) = @_;
159 $storid = systemd_unescape
($storid);
161 my $unitfile = "/etc/systemd/system/$filename";
162 my $unit = $read_ini->($unitfile);
165 unitfile
=> $unitfile,
166 path
=> "/mnt/pve/$storid",
167 device
=> $unit->{'Mount'}->{'What'},
168 type
=> $unit->{'Mount'}->{'Type'},
169 options
=> $unit->{'Mount'}->{'Options'},
176 __PACKAGE__-
>register_method ({
183 check
=> ['perm', '/', ['Sys.Modify', 'Datastore.Allocate']],
185 description
=> "Create a Filesystem on an unused disk. Will be mounted under '/mnt/pve/NAME'.",
187 additionalProperties
=> 0,
189 node
=> get_standard_option
('pve-node'),
190 name
=> get_standard_option
('pve-storage-id'),
193 description
=> 'The block device you want to create the filesystem on.',
196 description
=> "Configure storage using the directory.",
202 description
=> "The desired filesystem.",
204 enum
=> ['ext4', 'xfs'],
210 returns
=> { type
=> 'string' },
214 my $rpcenv = PVE
::RPCEnvironment
::get
();
215 my $user = $rpcenv->get_user();
217 my $name = $param->{name
};
218 my $dev = $param->{device
};
219 my $node = $param->{node
};
220 my $type = $param->{filesystem
} // 'ext4';
222 $dev = PVE
::Diskmanage
::verify_blockdev_path
($dev);
223 PVE
::Diskmanage
::assert_disk_unused
($dev);
224 PVE
::Storage
::assert_sid_unused
($name) if $param->{add_storage
};
227 my $path = "/mnt/pve/$name";
228 my $mountunitname = "mnt-pve-".systemd_escape
($name).".mount";
229 my $mountunitpath = "/etc/systemd/system/$mountunitname";
231 PVE
::Diskmanage
::locked_disk_action
(sub {
233 my $cmd = [$SGDISK, '-n1', '-t1:8300', $dev];
234 print "# ", join(' ', @$cmd), "\n";
237 my ($devname) = $dev =~ m
|^/dev/(.*)$|;
239 dir_glob_foreach
("/sys/block/$devname", qr
/\Q
$devname\E.+/, sub {
240 my ($partition) = @_;
245 $cmd = [$MKFS, '-t', $type, $part];
246 print "# ", join(' ', @$cmd), "\n";
249 # create systemd mount unit and enable & start it
252 'Description' => "Mount storage '$name' under /mnt/pve",
255 'WantedBy' => 'multi-user.target',
262 $cmd = [$BLKID, $part, '-o', 'export'];
263 print "# ", join(' ', @$cmd), "\n";
264 run_command
($cmd, outfunc
=> sub {
267 if ($line =~ m/^UUID=(.*)$/) {
269 $uuid_path = "/dev/disk/by-uuid/$uuid";
273 die "could not get UUID of device '$part'\n" if !$uuid;
276 'What' => $uuid_path,
279 'Options' => 'defaults',
282 $write_ini->($ini, $mountunitpath);
284 run_command
(['systemctl', 'daemon-reload']);
285 run_command
(['systemctl', 'enable', $mountunitname]);
286 run_command
(['systemctl', 'start', $mountunitname]);
288 if ($param->{add_storage
}) {
289 my $storage_params = {
292 content
=> 'rootdir,images,iso,backup,vztmpl,snippets',
298 PVE
::API2
::Storage
::Config-
>create($storage_params);
303 return $rpcenv->fork_worker('dircreate', $name, $user, $worker);