]>
git.proxmox.com Git - pve-storage.git/blob - PVE/API2/Storage/Config.pm
1 package PVE
::API2
::Storage
::Config
;
7 use PVE
::Tools
qw(extract_param);
8 use PVE
::Cluster
qw(cfs_read_file cfs_write_file);
10 use PVE
::Storage
::Plugin
;
11 use PVE
::Storage
::LVMPlugin
;
12 use PVE
::Storage
::CIFSPlugin
;
13 use HTTP
::Status
qw(:constants);
14 use Storable
qw(dclone);
15 use PVE
::JSONSchema
qw(get_standard_option);
16 use PVE
::RPCEnvironment
;
20 use base
qw(PVE::RESTHandler);
22 my @ctypes = qw(images vztmpl iso backup);
24 my $storage_type_enum = PVE
::Storage
::Plugin-
>lookup_types();
26 my $api_storage_config = sub {
27 my ($cfg, $storeid) = @_;
29 my $scfg = dclone
(PVE
::Storage
::storage_config
($cfg, $storeid));
30 $scfg->{storage
} = $storeid;
31 $scfg->{digest
} = $cfg->{digest
};
32 $scfg->{content
} = PVE
::Storage
::Plugin-
>encode_value($scfg->{type
}, 'content', $scfg->{content
});
35 $scfg->{nodes
} = PVE
::Storage
::Plugin-
>encode_value($scfg->{type
}, 'nodes', $scfg->{nodes
});
41 __PACKAGE__-
>register_method ({
45 description
=> "Storage index.",
47 description
=> "Only list entries where you have 'Datastore.Audit' or 'Datastore.AllocateSpace' permissions on '/storage/<storage>'",
51 additionalProperties
=> 0,
54 description
=> "Only list storage of specific type",
56 enum
=> $storage_type_enum,
65 properties
=> { storage
=> { type
=> 'string'} },
67 links
=> [ { rel
=> 'child', href
=> "{storage}" } ],
72 my $rpcenv = PVE
::RPCEnvironment
::get
();
73 my $authuser = $rpcenv->get_user();
75 my $cfg = PVE
::Storage
::config
();
77 my @sids = PVE
::Storage
::storage_ids
($cfg);
80 foreach my $storeid (@sids) {
81 my $privs = [ 'Datastore.Audit', 'Datastore.AllocateSpace' ];
82 next if !$rpcenv->check_any($authuser, "/storage/$storeid", $privs, 1);
84 my $scfg = &$api_storage_config($cfg, $storeid);
85 next if $param->{type
} && $param->{type
} ne $scfg->{type
};
92 __PACKAGE__-
>register_method ({
96 description
=> "Read storage configuration.",
98 check
=> ['perm', '/storage/{storage}', ['Datastore.Allocate']],
101 additionalProperties
=> 0,
103 storage
=> get_standard_option
('pve-storage-id'),
106 returns
=> { type
=> 'object' },
110 my $cfg = PVE
::Storage
::config
();
112 return &$api_storage_config($cfg, $param->{storage
});
115 my sub extract_sensitive_params
:prototype($$) {
116 my ($param, $delete_list) = @_;
120 my %delete = map { $_ => 1 } ($delete_list || [])->@*;
122 # always extract pw and keys, so they don't get written to the www-data readable scfg
123 for my $opt (qw(password encryption-key)) {
124 # First handle deletions as explicitly setting `undef`, afterwards new values may override
126 if (exists($delete{$opt})) {
127 $sensitive->{$opt} = undef;
130 if (defined(my $value = extract_param
($param, $opt))) {
131 $sensitive->{$opt} = $value;
138 __PACKAGE__-
>register_method ({
143 description
=> "Create a new storage.",
145 check
=> ['perm', '/storage', ['Datastore.Allocate']],
147 parameters
=> PVE
::Storage
::Plugin-
>createSchema(),
152 description
=> "The ID of the created storage.",
156 description
=> "The type of the created storage.",
158 enum
=> $storage_type_enum,
161 description
=> "Partial, possible server generated, configuration properties.",
164 additionalProperties
=> 1,
166 'encryption-key' => {
167 description
=> "The, possible auto-generated, encryption-key.",
178 my $type = extract_param
($param, 'type');
179 my $storeid = extract_param
($param, 'storage');
181 # revent an empty nodelist.
182 # fix me in section config create never need an empty entity.
183 delete $param->{nodes
} if !$param->{nodes
};
185 my $sensitive = extract_sensitive_params
($param, []);
187 my $plugin = PVE
::Storage
::Plugin-
>lookup($type);
188 my $opts = $plugin->check_config($storeid, $param, 1, 1);
191 PVE
::Storage
::lock_storage_config
(sub {
192 my $cfg = PVE
::Storage
::config
();
194 if (my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid, 1)) {
195 die "storage ID '$storeid' already defined\n";
198 $cfg->{ids
}->{$storeid} = $opts;
200 $returned_config = $plugin->on_add_hook($storeid, $opts, %$sensitive);
203 # try to activate if enabled on local node,
204 # we only do this to detect errors/problems sooner
205 if (PVE
::Storage
::storage_check_enabled
($cfg, $storeid, undef, 1)) {
206 PVE
::Storage
::activate_storage
($cfg, $storeid);
210 eval { $plugin->on_delete_hook($storeid, $opts) };
215 PVE
::Storage
::write_config
($cfg);
217 }, "create storage failed");
223 $res->{config
} = $returned_config if $returned_config;
227 __PACKAGE__-
>register_method ({
232 description
=> "Update storage configuration.",
234 check
=> ['perm', '/storage', ['Datastore.Allocate']],
236 parameters
=> PVE
::Storage
::Plugin-
>updateSchema(),
241 description
=> "The ID of the created storage.",
245 description
=> "The type of the created storage.",
247 enum
=> $storage_type_enum,
250 description
=> "Partial, possible server generated, configuration properties.",
253 additionalProperties
=> 1,
255 'encryption-key' => {
256 description
=> "The, possible auto-generated, encryption-key.",
267 my $storeid = extract_param
($param, 'storage');
268 my $digest = extract_param
($param, 'digest');
269 my $delete = extract_param
($param, 'delete');
273 $delete = [ PVE
::Tools
::split_list
($delete) ];
277 PVE
::Storage
::lock_storage_config
(sub {
278 my $cfg = PVE
::Storage
::config
();
280 PVE
::SectionConfig
::assert_if_modified
($cfg, $digest);
282 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
283 $type = $scfg->{type
};
285 my $sensitive = extract_sensitive_params
($param, $delete);
287 my $plugin = PVE
::Storage
::Plugin-
>lookup($type);
288 my $opts = $plugin->check_config($storeid, $param, 0, 1);
291 my $options = $plugin->private()->{options
}->{$type};
292 foreach my $k (@$delete) {
293 my $d = $options->{$k} || die "no such option '$k'\n";
294 die "unable to delete required option '$k'\n" if !$d->{optional
};
295 die "unable to delete fixed option '$k'\n" if $d->{fixed
};
296 die "cannot set and delete property '$k' at the same time!\n"
297 if defined($opts->{$k});
303 $returned_config = $plugin->on_update_hook($storeid, $opts, %$sensitive);
305 for my $k (keys %$opts) {
306 $scfg->{$k} = $opts->{$k};
309 PVE
::Storage
::write_config
($cfg);
311 }, "update storage failed");
317 $res->{config
} = $returned_config if $returned_config;
321 __PACKAGE__-
>register_method ({
324 path
=> '{storage}', # /storage/config/{storage}
326 description
=> "Delete storage configuration.",
328 check
=> ['perm', '/storage', ['Datastore.Allocate']],
331 additionalProperties
=> 0,
333 storage
=> get_standard_option
('pve-storage-id', {
334 completion
=> \
&PVE
::Storage
::complete_storage
,
338 returns
=> { type
=> 'null' },
342 my $storeid = extract_param
($param, 'storage');
344 PVE
::Storage
::lock_storage_config
(sub {
345 my $cfg = PVE
::Storage
::config
();
347 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
349 die "can't remove storage - storage is used as base of another storage\n"
350 if PVE
::Storage
::storage_is_used
($cfg, $storeid);
352 my $plugin = PVE
::Storage
::Plugin-
>lookup($scfg->{type
});
354 $plugin->on_delete_hook($storeid, $scfg);
356 delete $cfg->{ids
}->{$storeid};
358 PVE
::Storage
::write_config
($cfg);
360 }, "delete storage failed");
362 PVE
::AccessControl
::remove_storage_access
($storeid);