]>
Commit | Line | Data |
---|---|---|
c33dd818 AD |
1 | package PVE::API2::Network::SDN::Subnets; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::SafeSyslog; | |
7 | use PVE::Tools qw(extract_param); | |
8 | use PVE::Cluster qw(cfs_read_file cfs_write_file); | |
70b03506 | 9 | use PVE::Exception qw(raise raise_param_exc); |
c33dd818 AD |
10 | use PVE::Network::SDN; |
11 | use PVE::Network::SDN::Subnets; | |
12 | use PVE::Network::SDN::SubnetPlugin; | |
58a7773a | 13 | use PVE::Network::SDN::Vnets; |
4ad78442 | 14 | use PVE::Network::SDN::Zones; |
70b03506 AD |
15 | use PVE::Network::SDN::Ipams; |
16 | use PVE::Network::SDN::Ipams::Plugin; | |
c33dd818 AD |
17 | |
18 | use Storable qw(dclone); | |
19 | use PVE::JSONSchema qw(get_standard_option); | |
20 | use PVE::RPCEnvironment; | |
21 | ||
22 | use PVE::RESTHandler; | |
23 | ||
24 | use base qw(PVE::RESTHandler); | |
25 | ||
26 | my $api_sdn_subnets_config = sub { | |
27 | my ($cfg, $id) = @_; | |
28 | ||
29 | my $scfg = dclone(PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id)); | |
30 | $scfg->{subnet} = $id; | |
c33dd818 AD |
31 | $scfg->{digest} = $cfg->{digest}; |
32 | ||
33 | return $scfg; | |
34 | }; | |
35 | ||
36 | __PACKAGE__->register_method ({ | |
37 | name => 'index', | |
38 | path => '', | |
39 | method => 'GET', | |
40 | description => "SDN subnets index.", | |
41 | permissions => { | |
42 | description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/subnets/<subnet>'", | |
43 | user => 'all', | |
44 | }, | |
45 | parameters => { | |
46 | additionalProperties => 0, | |
3926d9a7 AD |
47 | properties => { |
48 | vnet => get_standard_option('pve-sdn-vnet-id'), | |
6f5f42e4 AD |
49 | running => { |
50 | type => 'boolean', | |
51 | optional => 1, | |
52 | description => "Display running config.", | |
53 | }, | |
54 | pending => { | |
55 | type => 'boolean', | |
56 | optional => 1, | |
57 | description => "Display pending config.", | |
58 | }, | |
59 | }, | |
c33dd818 AD |
60 | }, |
61 | returns => { | |
62 | type => 'array', | |
63 | items => { | |
64 | type => "object", | |
65 | properties => {}, | |
66 | }, | |
67 | links => [ { rel => 'child', href => "{subnet}" } ], | |
68 | }, | |
69 | code => sub { | |
70 | my ($param) = @_; | |
71 | ||
72 | my $rpcenv = PVE::RPCEnvironment::get(); | |
73 | my $authuser = $rpcenv->get_user(); | |
74 | ||
3926d9a7 | 75 | my $vnetid = $param->{vnet}; |
c33dd818 | 76 | |
6f5f42e4 AD |
77 | my $cfg = {}; |
78 | if($param->{pending}) { | |
79 | my $running_cfg = PVE::Network::SDN::config(); | |
80 | my $config = PVE::Network::SDN::Subnets::config(); | |
81 | $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'subnets'); | |
82 | } elsif ($param->{running}) { | |
83 | my $running_cfg = PVE::Network::SDN::config(); | |
84 | $cfg = $running_cfg->{subnets}; | |
85 | } else { | |
86 | $cfg = PVE::Network::SDN::Subnets::config(); | |
87 | } | |
c33dd818 AD |
88 | |
89 | my @sids = PVE::Network::SDN::Subnets::sdn_subnets_ids($cfg); | |
90 | my $res = []; | |
91 | foreach my $id (@sids) { | |
92 | my $privs = [ 'SDN.Audit', 'SDN.Allocate' ]; | |
3926d9a7 | 93 | next if !$rpcenv->check_any($authuser, "/sdn/vnets/$vnetid/subnets/$id", $privs, 1); |
c33dd818 AD |
94 | |
95 | my $scfg = &$api_sdn_subnets_config($cfg, $id); | |
3926d9a7 | 96 | next if !$scfg->{vnet} || $scfg->{vnet} ne $vnetid; |
c33dd818 AD |
97 | push @$res, $scfg; |
98 | } | |
99 | ||
100 | return $res; | |
101 | }}); | |
102 | ||
103 | __PACKAGE__->register_method ({ | |
104 | name => 'read', | |
105 | path => '{subnet}', | |
106 | method => 'GET', | |
107 | description => "Read sdn subnet configuration.", | |
108 | permissions => { | |
3926d9a7 | 109 | check => ['perm', '/sdn/vnets/{vnet}/subnets/{subnet}', ['SDN.Allocate']], |
c33dd818 AD |
110 | }, |
111 | ||
112 | parameters => { | |
113 | additionalProperties => 0, | |
114 | properties => { | |
3926d9a7 | 115 | vnet => get_standard_option('pve-sdn-vnet-id'), |
c33dd818 AD |
116 | subnet => get_standard_option('pve-sdn-subnet-id', { |
117 | completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets, | |
118 | }), | |
6f5f42e4 AD |
119 | running => { |
120 | type => 'boolean', | |
121 | optional => 1, | |
122 | description => "Display running config.", | |
123 | }, | |
124 | pending => { | |
125 | type => 'boolean', | |
126 | optional => 1, | |
127 | description => "Display pending config.", | |
128 | }, | |
129 | }, | |
c33dd818 AD |
130 | }, |
131 | returns => { type => 'object' }, | |
132 | code => sub { | |
133 | my ($param) = @_; | |
134 | ||
6f5f42e4 AD |
135 | my $cfg = {}; |
136 | if($param->{pending}) { | |
137 | my $running_cfg = PVE::Network::SDN::config(); | |
138 | my $config = PVE::Network::SDN::Subnets::config(); | |
139 | $cfg = PVE::Network::SDN::pending_config($running_cfg, $config, 'subnets'); | |
140 | } elsif ($param->{running}) { | |
141 | my $running_cfg = PVE::Network::SDN::config(); | |
142 | $cfg = $running_cfg->{subnets}; | |
143 | } else { | |
144 | $cfg = PVE::Network::SDN::Subnets::config(); | |
145 | } | |
146 | ||
3926d9a7 AD |
147 | my $scfg = &$api_sdn_subnets_config($cfg, $param->{subnet}); |
148 | ||
149 | raise_param_exc({ vnet => "wrong vnet"}) if $param->{vnet} ne $scfg->{vnet}; | |
c33dd818 | 150 | |
3926d9a7 | 151 | return $scfg; |
c33dd818 AD |
152 | }}); |
153 | ||
154 | __PACKAGE__->register_method ({ | |
155 | name => 'create', | |
156 | protected => 1, | |
157 | path => '', | |
158 | method => 'POST', | |
159 | description => "Create a new sdn subnet object.", | |
160 | permissions => { | |
3926d9a7 | 161 | check => ['perm', '/sdn/vnets/{vnet}/subnets', ['SDN.Allocate']], |
c33dd818 AD |
162 | }, |
163 | parameters => PVE::Network::SDN::SubnetPlugin->createSchema(), | |
164 | returns => { type => 'null' }, | |
165 | code => sub { | |
166 | my ($param) = @_; | |
167 | ||
168 | my $type = extract_param($param, 'type'); | |
169 | my $cidr = extract_param($param, 'subnet'); | |
c33dd818 AD |
170 | |
171 | # create /etc/pve/sdn directory | |
172 | PVE::Cluster::check_cfs_quorum(); | |
173 | mkdir("/etc/pve/sdn") if ! -d '/etc/pve/sdn'; | |
174 | ||
175 | PVE::Network::SDN::lock_sdn_config( | |
176 | sub { | |
177 | ||
178 | my $cfg = PVE::Network::SDN::Subnets::config(); | |
4ad78442 AD |
179 | my $zone_cfg = PVE::Network::SDN::Zones::config(); |
180 | my $vnet_cfg = PVE::Network::SDN::Vnets::config(); | |
181 | my $vnet = $param->{vnet}; | |
182 | my $zoneid = $vnet_cfg->{ids}->{$vnet}->{zone}; | |
183 | my $zone = $zone_cfg->{ids}->{$zoneid}; | |
e8736dac AD |
184 | my $id = $cidr =~ s/\//-/r; |
185 | $id = "$zoneid-$id"; | |
186 | ||
c33dd818 AD |
187 | my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 1, 1); |
188 | ||
189 | my $scfg = undef; | |
190 | if ($scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id, 1)) { | |
191 | die "sdn subnet object ID '$id' already defined\n"; | |
192 | } | |
193 | ||
194 | $cfg->{ids}->{$id} = $opts; | |
e8736dac AD |
195 | |
196 | my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id); | |
197 | PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $subnet); | |
70b03506 | 198 | |
c33dd818 | 199 | PVE::Network::SDN::Subnets::write_config($cfg); |
c33dd818 AD |
200 | |
201 | }, "create sdn subnet object failed"); | |
202 | ||
203 | return undef; | |
204 | }}); | |
205 | ||
206 | __PACKAGE__->register_method ({ | |
207 | name => 'update', | |
208 | protected => 1, | |
209 | path => '{subnet}', | |
210 | method => 'PUT', | |
211 | description => "Update sdn subnet object configuration.", | |
212 | permissions => { | |
3926d9a7 | 213 | check => ['perm', '/sdn/vnets/{vnet}/subnets', ['SDN.Allocate']], |
c33dd818 AD |
214 | }, |
215 | parameters => PVE::Network::SDN::SubnetPlugin->updateSchema(), | |
216 | returns => { type => 'null' }, | |
217 | code => sub { | |
218 | my ($param) = @_; | |
219 | ||
220 | my $id = extract_param($param, 'subnet'); | |
221 | my $digest = extract_param($param, 'digest'); | |
222 | ||
223 | PVE::Network::SDN::lock_sdn_config( | |
224 | sub { | |
225 | ||
226 | my $cfg = PVE::Network::SDN::Subnets::config(); | |
4ad78442 AD |
227 | my $zone_cfg = PVE::Network::SDN::Zones::config(); |
228 | my $vnet_cfg = PVE::Network::SDN::Vnets::config(); | |
229 | my $vnet = $param->{vnet}; | |
230 | my $zoneid = $vnet_cfg->{ids}->{$vnet}->{zone}; | |
231 | my $zone = $zone_cfg->{ids}->{$zoneid}; | |
232 | ||
70b03506 | 233 | my $scfg = &$api_sdn_subnets_config($cfg, $id); |
c33dd818 AD |
234 | |
235 | PVE::SectionConfig::assert_if_modified($cfg, $digest); | |
236 | ||
237 | my $opts = PVE::Network::SDN::SubnetPlugin->check_config($id, $param, 0, 1); | |
238 | $cfg->{ids}->{$id} = $opts; | |
239 | ||
9dfa9202 AD |
240 | raise_param_exc({ ipam => "you can't change ipam"}) if $opts->{ipam} && $scfg->{ipam} && $opts->{ipam} ne $scfg->{ipam}; |
241 | ||
e8736dac | 242 | my $subnet = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id); |
d595c034 | 243 | PVE::Network::SDN::SubnetPlugin->on_update_hook($zone, $id, $subnet, $scfg); |
70b03506 | 244 | |
c33dd818 | 245 | PVE::Network::SDN::Subnets::write_config($cfg); |
c33dd818 AD |
246 | |
247 | }, "update sdn subnet object failed"); | |
248 | ||
249 | return undef; | |
250 | }}); | |
251 | ||
252 | __PACKAGE__->register_method ({ | |
253 | name => 'delete', | |
254 | protected => 1, | |
255 | path => '{subnet}', | |
256 | method => 'DELETE', | |
257 | description => "Delete sdn subnet object configuration.", | |
258 | permissions => { | |
3926d9a7 | 259 | check => ['perm', '/sdn/vnets/{vnet}/subnets', ['SDN.Allocate']], |
c33dd818 AD |
260 | }, |
261 | parameters => { | |
262 | additionalProperties => 0, | |
263 | properties => { | |
3926d9a7 | 264 | vnet => get_standard_option('pve-sdn-vnet-id'), |
c33dd818 AD |
265 | subnet => get_standard_option('pve-sdn-subnet-id', { |
266 | completion => \&PVE::Network::SDN::Subnets::complete_sdn_subnets, | |
267 | }), | |
268 | }, | |
269 | }, | |
270 | returns => { type => 'null' }, | |
271 | code => sub { | |
272 | my ($param) = @_; | |
273 | ||
274 | my $id = extract_param($param, 'subnet'); | |
275 | ||
276 | PVE::Network::SDN::lock_sdn_config( | |
277 | sub { | |
c33dd818 AD |
278 | my $cfg = PVE::Network::SDN::Subnets::config(); |
279 | ||
280 | my $scfg = PVE::Network::SDN::Subnets::sdn_subnets_config($cfg, $id); | |
281 | ||
58a7773a AD |
282 | my $subnets_cfg = PVE::Network::SDN::Subnets::config(); |
283 | my $vnets_cfg = PVE::Network::SDN::Vnets::config(); | |
c33dd818 | 284 | |
58a7773a | 285 | PVE::Network::SDN::SubnetPlugin->on_delete_hook($id, $subnets_cfg, $vnets_cfg); |
70b03506 AD |
286 | |
287 | my $ipam_cfg = PVE::Network::SDN::Ipams::config(); | |
288 | my $ipam = $cfg->{ids}->{$id}->{ipam}; | |
289 | if ($ipam) { | |
290 | raise_param_exc({ ipam => "$ipam not existing"}) if !$ipam_cfg->{ids}->{$ipam}; | |
291 | my $plugin_config = $ipam_cfg->{ids}->{$ipam}; | |
292 | my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); | |
293 | $plugin->del_subnet($plugin_config, $id, $scfg); | |
294 | } | |
295 | ||
296 | delete $cfg->{ids}->{$id}; | |
297 | ||
c33dd818 | 298 | PVE::Network::SDN::Subnets::write_config($cfg); |
c33dd818 AD |
299 | |
300 | }, "delete sdn subnet object failed"); | |
301 | ||
302 | ||
303 | return undef; | |
304 | }}); | |
305 | ||
306 | 1; |