]> git.proxmox.com Git - pve-storage.git/blob - PVE/API2/Storage/Config.pm
imported from svn 'pve-storage/pve2'
[pve-storage.git] / PVE / API2 / Storage / Config.pm
1 package PVE::API2::Storage::Config;
2
3 use strict;
4 use warnings;
5
6 use PVE::SafeSyslog;
7 use PVE::Cluster qw(cfs_read_file cfs_write_file);
8 use PVE::Storage;
9 use HTTP::Status qw(:constants);
10 use Storable qw(dclone);
11 use PVE::JSONSchema qw(get_standard_option);
12
13 use Data::Dumper; # fixme: remove
14
15 use PVE::RESTHandler;
16
17 use base qw(PVE::RESTHandler);
18
19 my @ctypes = qw(images vztmpl iso backup);
20
21 my $storage_type_enum = ['dir', 'nfs', 'lvm', 'iscsi'];
22
23 my $api_storage_config = sub {
24 my ($cfg, $storeid) = @_;
25
26 my $scfg = dclone(PVE::Storage::storage_config ($cfg, $storeid));
27 $scfg->{storage} = $storeid;
28 delete $scfg->{priority};
29 $scfg->{digest} = $cfg->{digest};
30 $scfg->{content} = PVE::Storage::content_hash_to_string($scfg->{content});
31
32 if ($scfg->{nodes}) {
33 $scfg->{nodes} = join(',', keys(%{$scfg->{nodes}}));
34 }
35
36 return $scfg;
37 };
38
39 __PACKAGE__->register_method ({
40 name => 'index',
41 path => '',
42 method => 'GET',
43 description => "Storage index.",
44 parameters => {
45 additionalProperties => 0,
46 properties => {
47 type => {
48 description => "Only list storage of specific type",
49 type => 'string',
50 enum => $storage_type_enum,
51 optional => 1,
52 },
53
54 },
55 },
56 returns => {
57 type => 'array',
58 items => {
59 type => "object",
60 properties => { storage => { type => 'string'} },
61 },
62 links => [ { rel => 'child', href => "{storage}" } ],
63 },
64 code => sub {
65 my ($param) = @_;
66
67 my $cfg = cfs_read_file("storage.cfg");
68
69 my @sids = PVE::Storage::storage_ids($cfg);
70
71 my $res = [];
72 foreach my $storeid (@sids) {
73 my $scfg = &$api_storage_config($cfg, $storeid);
74 next if $param->{type} && $param->{type} ne $scfg->{type};
75 push @$res, $scfg;
76 }
77
78 return $res;
79 }});
80
81 __PACKAGE__->register_method ({
82 name => 'read',
83 path => '{storage}',
84 method => 'GET',
85 description => "Read storage configuration.",
86 parameters => {
87 additionalProperties => 0,
88 properties => {
89 storage => get_standard_option('pve-storage-id'),
90 },
91 },
92 returns => {},
93 code => sub {
94 my ($param) = @_;
95
96 my $cfg = cfs_read_file("storage.cfg");
97
98 return &$api_storage_config($cfg, $param->{storage});
99 }});
100
101 __PACKAGE__->register_method ({
102 name => 'create',
103 protected => 1,
104 path => '',
105 method => 'POST',
106 description => "Create a new storage.",
107 parameters => {
108 additionalProperties => 0,
109 properties => {
110 storage => get_standard_option('pve-storage-id'),
111 nodes => get_standard_option('pve-node-list', { optional => 1 }),
112 type => {
113 type => 'string',
114 enum => $storage_type_enum,
115 },
116 path => {
117 type => 'string', format => 'pve-storage-path',
118 optional => 1,
119 },
120 export => {
121 type => 'string', format => 'pve-storage-path',
122 optional => 1,
123 },
124 server => {
125 type => 'string', format => 'pve-storage-server',
126 optional => 1,
127 },
128 options => {
129 type => 'string', format => 'pve-storage-options',
130 optional => 1,
131 },
132 target => {
133 type => 'string',
134 optional => 1,
135 },
136 vgname => {
137 type => 'string', format => 'pve-storage-vgname',
138 optional => 1,
139 },
140 base => {
141 type => 'string', format => 'pve-volume-id',
142 optional => 1,
143 },
144 portal => {
145 type => 'string', format => 'pve-storage-portal-dns',
146 optional => 1,
147 },
148 content => {
149 type => 'string', format => 'pve-storage-content-list',
150 optional => 1,
151 },
152 disable => {
153 type => 'boolean',
154 optional => 1,
155 },
156 shared => {
157 type => 'boolean',
158 optional => 1,
159 },
160 'format' => {
161 type => 'string', format => 'pve-storage-format',
162 optional => 1,
163 },
164 },
165 },
166 returns => { type => 'null' },
167 code => sub {
168 my ($param) = @_;
169
170 my $type = $param->{type};
171 delete $param->{type};
172
173 my $storeid = $param->{storage};
174 delete $param->{storage};
175
176 if ($param->{portal}) {
177 $param->{portal} = PVE::Storage::resolv_portal($param->{portal});
178 }
179
180 my $opts = PVE::Storage::parse_options($storeid, $type, $param, 1);
181
182 PVE::Storage::lock_storage_config(
183 sub {
184
185 my $cfg = cfs_read_file('storage.cfg');
186
187 if (my $scfg = PVE::Storage::storage_config ($cfg, $storeid, 1)) {
188 die "storage ID '$storeid' already defined\n";
189 }
190
191 $cfg->{ids}->{$storeid} = $opts;
192
193 if ($type eq 'lvm' && $opts->{base}) {
194
195 my ($baseid, $volname) = PVE::Storage::parse_volume_id ($opts->{base});
196
197 my $basecfg = PVE::Storage::storage_config ($cfg, $baseid, 1);
198 die "base storage ID '$baseid' does not exist\n" if !$basecfg;
199
200 # we only support iscsi for now
201 if (!($basecfg->{type} eq 'iscsi')) {
202 die "unsupported base type '$basecfg->{type}'";
203 }
204
205 my $path = PVE::Storage::path ($cfg, $opts->{base});
206
207 PVE::Storage::activate_storage($cfg, $baseid);
208
209 PVE::Storage::lvm_create_volume_group ($path, $opts->{vgname}, $opts->{shared});
210 }
211
212 # try to activate if enabled on local node,
213 # we only do this to detect errors/problems sooner
214 if (PVE::Storage::storage_check_enabled($cfg, $storeid, undef, 1)) {
215 PVE::Storage::activate_storage($cfg, $storeid);
216 }
217
218 cfs_write_file('storage.cfg', $cfg);
219
220 }, "create storage failed");
221
222 }});
223
224 __PACKAGE__->register_method ({
225 name => 'update',
226 protected => 1,
227 path => '{storage}',
228 method => 'PUT',
229 description => "Update storage configuration.",
230 parameters => {
231 additionalProperties => 0,
232 properties => {
233 storage => get_standard_option('pve-storage-id'),
234 nodes => get_standard_option('pve-node-list', { optional => 1 }),
235 content => {
236 type => 'string', format => 'pve-storage-content-list',
237 optional => 1,
238 },
239 'format' => {
240 type => 'string', format => 'pve-storage-format',
241 optional => 1,
242 },
243 disable => {
244 type => 'boolean',
245 optional => 1,
246 },
247 shared => {
248 type => 'boolean',
249 optional => 1,
250 },
251 options => {
252 type => 'string', format => 'pve-storage-options',
253 optional => 1,
254 },
255 digest => {
256 type => 'string',
257 optional => 1,
258 }
259 },
260 },
261 returns => { type => 'null' },
262 code => sub {
263 my ($param) = @_;
264
265 my $storeid = $param->{storage};
266 delete($param->{storage});
267
268 my $digest = $param->{digest};
269 delete($param->{digest});
270
271 PVE::Storage::lock_storage_config(
272 sub {
273
274 my $cfg = cfs_read_file('storage.cfg');
275
276 PVE::Storage::assert_if_modified ($cfg, $digest);
277
278 my $scfg = PVE::Storage::storage_config ($cfg, $storeid);
279
280 my $opts = PVE::Storage::parse_options($storeid, $scfg->{type}, $param);
281
282 foreach my $k (%$opts) {
283 $scfg->{$k} = $opts->{$k};
284 }
285
286 cfs_write_file('storage.cfg', $cfg);
287
288 }, "update storage failed");
289
290 return undef;
291 }});
292
293 __PACKAGE__->register_method ({
294 name => 'delete',
295 protected => 1,
296 path => '{storage}', # /storage/config/{storage}
297 method => 'DELETE',
298 description => "Delete storage configuration.",
299 parameters => {
300 additionalProperties => 0,
301 properties => {
302 storage => get_standard_option('pve-storage-id'),
303 },
304 },
305 returns => { type => 'null' },
306 code => sub {
307 my ($param) = @_;
308
309 my $storeid = $param->{storage};
310 delete($param->{storage});
311
312 PVE::Storage::lock_storage_config(
313 sub {
314
315 my $cfg = cfs_read_file('storage.cfg');
316
317 die "can't remove storage - storage is used as base of another storage\n"
318 if PVE::Storage::storage_is_used ($cfg, $storeid);
319
320 delete ($cfg->{ids}->{$storeid});
321
322 cfs_write_file('storage.cfg', $cfg);
323
324 }, "delete storage failed");
325
326 return undef;
327 }});
328
329 1;