]> git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Cluster/Mapping/PCI.pm
api: add resource map api endpoints for PCI and USB
[pve-manager.git] / PVE / API2 / Cluster / Mapping / PCI.pm
1 package PVE::API2::Cluster::Mapping::PCI;
2
3 use strict;
4 use warnings;
5
6 use Storable qw(dclone);
7
8 use PVE::Cluster qw(cfs_lock_file);
9 use PVE::Mapping::PCI;
10 use PVE::JSONSchema qw(get_standard_option);
11 use PVE::Tools qw(extract_param);
12
13 use PVE::RESTHandler;
14
15 use base qw(PVE::RESTHandler);
16
17 __PACKAGE__->register_method ({
18 name => 'index',
19 path => '',
20 method => 'GET',
21 # only proxy if we give the 'check-node' parameter
22 proxyto_callback => sub {
23 my ($rpcenv, $proxyto, $param) = @_;
24 return $param->{'check-node'} // 'localhost';
25 },
26 description => "List PCI Hardware Mapping",
27 permissions => {
28 description => "Only lists entries where you have 'Mapping.Modify', 'Mapping.Use' or".
29 " 'Mapping.Audit' permissions on '/mapping/pci/<id>'.",
30 user => 'all',
31 },
32 parameters => {
33 additionalProperties => 0,
34 properties => {
35 'check-node' => get_standard_option('pve-node', {
36 description => "If given, checks the configurations on the given node for ".
37 "correctness, and adds relevant errors to the devices.",
38 optional => 1,
39 }),
40 },
41 },
42 returns => {
43 type => 'array',
44 items => {
45 type => "object",
46 properties => {
47 id => {
48 type => 'string',
49 description => "The logical ID of the mapping."
50 },
51 map => {
52 type => 'array',
53 description => "The entries of the mapping.",
54 items => {
55 type => 'string',
56 description => "A mapping for a node.",
57 },
58 },
59 description => {
60 type => 'string',
61 description => "A description of the logical mapping.",
62 },
63 error => {
64 description => "A list of errors when 'check_node' is given.",
65 items => {
66 type => 'object',
67 properties => {
68 severity => {
69 type => "string",
70 description => "The severity of the error",
71 },
72 message => {
73 type => "string",
74 description => "The message of the error",
75 },
76 },
77 }
78 },
79 },
80 },
81 links => [ { rel => 'child', href => "{id}" } ],
82 },
83 code => sub {
84 my ($param) = @_;
85
86 my $rpcenv = PVE::RPCEnvironment::get();
87 my $authuser = $rpcenv->get_user();
88 my $node = $param->{'check-node'};
89
90 die "Wrong node to check\n"
91 if defined($node) && $node ne 'localhost' && $node ne PVE::INotify::nodename();
92
93 my $cfg = PVE::Mapping::PCI::config();
94
95 my $res = [];
96
97 my $privs = ['Mapping.Modify', 'Mapping.Use', 'Mapping.Audit'];
98
99 for my $id (keys $cfg->{ids}->%*) {
100 next if !$rpcenv->check_full($authuser, "/mapping/pci/$id", $privs, 1, 1);
101 next if !$cfg->{ids}->{$id};
102
103 my $entry = dclone($cfg->{ids}->{$id});
104 $entry->{id} = $id;
105 $entry->{digest} = $cfg->{digest};
106
107 if (defined($node)) {
108 $entry->{errors} = [];
109 if (my $mappings = PVE::Mapping::PCI::get_node_mapping($cfg, $id, $node)) {
110 if (!scalar($mappings->@*)) {
111 push $entry->{errors}->@*, {
112 severity => 'warning',
113 message => "No mapping for node $node.",
114 };
115 }
116 for my $mapping ($mappings->@*) {
117 eval {
118 PVE::Mapping::PCI::assert_valid($id, $mapping);
119 };
120 if (my $err = $@) {
121 push $entry->{errors}->@*, {
122 severity => 'error',
123 message => "Invalid configuration: $err",
124 };
125 }
126 }
127 }
128 }
129
130 push @$res, $entry;
131 }
132
133 return $res;
134 },
135 });
136
137 __PACKAGE__->register_method ({
138 name => 'get',
139 protected => 1,
140 path => '{id}',
141 method => 'GET',
142 description => "Get PCI Mapping.",
143 permissions => {
144 check =>['or',
145 ['perm', '/mapping/pci/{id}', ['Mapping.Use']],
146 ['perm', '/mapping/pci/{id}', ['Mapping.Modify']],
147 ['perm', '/mapping/pci/{id}', ['Mapping.Audit']],
148 ],
149 },
150 parameters => {
151 additionalProperties => 0,
152 properties => {
153 id => {
154 type => 'string',
155 format => 'pve-configid',
156 },
157 }
158 },
159 returns => { type => 'object' },
160 code => sub {
161 my ($param) = @_;
162
163 my $cfg = PVE::Mapping::PCI::config();
164 my $id = $param->{id};
165
166 my $entry = $cfg->{ids}->{$id};
167 die "mapping '$param->{id}' not found\n" if !defined($entry);
168
169 my $data = dclone($entry);
170
171 $data->{digest} = $cfg->{digest};
172
173 return $data;
174 }});
175
176 __PACKAGE__->register_method ({
177 name => 'create',
178 protected => 1,
179 path => '',
180 method => 'POST',
181 description => "Create a new hardware mapping.",
182 permissions => {
183 check => ['perm', '/mapping/pci', ['Mapping.Modify']],
184 },
185 parameters => PVE::Mapping::PCI->createSchema(1),
186 returns => {
187 type => 'null',
188 },
189 code => sub {
190 my ($param) = @_;
191
192 my $id = extract_param($param, 'id');
193
194 my $plugin = PVE::Mapping::PCI->lookup('pci');
195 my $opts = $plugin->check_config($id, $param, 1, 1);
196
197 PVE::Mapping::PCI::lock_pci_config(sub {
198 my $cfg = PVE::Mapping::PCI::config();
199
200 die "pci ID '$id' already defined\n" if defined($cfg->{ids}->{$id});
201
202 $cfg->{ids}->{$id} = $opts;
203
204 PVE::Mapping::PCI::write_pci_config($cfg);
205
206 }, "create hardware mapping failed");
207
208 return;
209 },
210 });
211
212 __PACKAGE__->register_method ({
213 name => 'update',
214 protected => 1,
215 path => '{id}',
216 method => 'PUT',
217 description => "Update a hardware mapping.",
218 permissions => {
219 check => ['perm', '/mapping/pci/{id}', ['Mapping.Modify']],
220 },
221 parameters => PVE::Mapping::PCI->updateSchema(),
222 returns => {
223 type => 'null',
224 },
225 code => sub {
226 my ($param) = @_;
227
228 my $digest = extract_param($param, 'digest');
229 my $delete = extract_param($param, 'delete');
230 my $id = extract_param($param, 'id');
231
232 if ($delete) {
233 $delete = [ PVE::Tools::split_list($delete) ];
234 }
235
236 PVE::Mapping::PCI::lock_pci_config(sub {
237 my $cfg = PVE::Mapping::PCI::config();
238
239 PVE::Tools::assert_if_modified($cfg->{digest}, $digest) if defined($digest);
240
241 die "pci ID '$id' does not exist\n" if !defined($cfg->{ids}->{$id});
242
243 my $plugin = PVE::Mapping::PCI->lookup('pci');
244 my $opts = $plugin->check_config($id, $param, 1, 1);
245
246 my $data = $cfg->{ids}->{$id};
247
248 my $options = $plugin->private()->{options}->{pci};
249 PVE::SectionConfig::delete_from_config($data, $options, $opts, $delete);
250
251 $data->{$_} = $opts->{$_} for keys $opts->%*;
252
253 PVE::Mapping::PCI::write_pci_config($cfg);
254
255 }, "update hardware mapping failed");
256
257 return;
258 },
259 });
260
261 __PACKAGE__->register_method ({
262 name => 'delete',
263 protected => 1,
264 path => '{id}',
265 method => 'DELETE',
266 description => "Remove Hardware Mapping.",
267 permissions => {
268 check => [ 'perm', '/mapping/pci', ['Mapping.Modify']],
269 },
270 parameters => {
271 additionalProperties => 0,
272 properties => {
273 id => {
274 type => 'string',
275 format => 'pve-configid',
276 },
277 }
278 },
279 returns => { type => 'null' },
280 code => sub {
281 my ($param) = @_;
282
283 my $id = $param->{id};
284
285 PVE::Mapping::PCI::lock_pci_config(sub {
286 my $cfg = PVE::Mapping::PCI::config();
287
288 if ($cfg->{ids}->{$id}) {
289 delete $cfg->{ids}->{$id};
290 }
291
292 PVE::Mapping::PCI::write_pci_config($cfg);
293
294 }, "delete pci mapping failed");
295
296 return;
297 }
298 });
299
300 1;