refine more exception classes in port management
[racktables] / wwwroot / inc / ophandlers.php
1 <?php
2
3 # This file is a part of RackTables, a datacenter and server room management
4 # framework. See accompanying file "COPYING" for the full copyright and
5 # licensing information.
6
7 /*
8
9 "Ophandler" in RackTables stands for "operation handler", or a function
10 that handles execution of "operation" (in the meaning explained in
11 navigation.php). Most of the ophandlers are meant to perform one specific
12 action, for example, to set a name of an object. Each such action often
13 requires a set of parameters (e. g. ID of the object and the new name),
14 and it is responsibility of each ophandler function to verify, that all
15 necessary parameters are provided by the user and have proper values. There
16 is a number of helper functions to make such verification simpler.
17
18 Errors occuring in ophandlers are typically indicated with exceptions of
19 assorted classes. Namely, an "InvalidRequestArgException" class means, that
20 at least one of the parameters provided by the user is not acceptable. This
21 is a "soft" error, which gets displayed in the standard message area of
22 otherwise usual interface. A different case is "InvalidArgException", which
23 means that one of the internal functions detected its argument(s) invalid
24 or corrupted, and that argument(s) did not come from user's input (and thus
25 cannot be fixed without fixing a bug in the code). Such "hard" errors don't
26 get special early handling and end up in the default catching block. The
27 latter may print a detailed stack trace instead of the interface HTML to
28 help a developer debug the issue.
29
30 As long as an ophandler makes through its request (extracting arguments,
31 performing validation and actually updating records in the database), it
32 may queue up messages (often referred to as "green" and "red" bars) by
33 means of showError() and showSuccess() functions. The messages are not
34 displayed immediately, because successfull ophandlers are expected to
35 return only the new URL, where the user will be immediately redirected to
36 (it is also possible to return an empty string to mean, that the current
37 logical location remains the same). The page at the "next" location is
38 supposed to translate message buffer into the standard message area.
39
40 A very special case of an ophandler is tableHandler(). This generic
41 function handles the most trivial actions, which map to a single INSERT,
42 UPDATE or DELETE SQL statement with a fixed number of arguments. The rules
43 of argument validation and mapping are listed in $opspec_list (operation
44 specifications list) array.
45
46 */
47
48 // This array is deprecated. Please do not add new message constants to it.
49 // use the new showError, showWarning, showSuccess functions instead
50 global $msgcode;
51 $msgcode = array();
52
53 global $opspec_list;
54 $opspec_list = array();
55
56 $opspec_list['object-edit-unlinkObjects'] = array
57 (
58 'table' => 'EntityLink',
59 'action' => 'DELETE',
60 'arglist' => array
61 (
62 array ('url_argname' => 'link_id', 'table_colname' => 'id', 'assertion' => 'uint'),
63 ),
64 );
65 $opspec_list['object-ports-useup'] = array
66 (
67 'table' => 'Port',
68 'action' => 'UPDATE',
69 'set_arglist' => array
70 (
71 array ('fix_argname' => 'reservation_comment', 'fix_argvalue' => NULL),
72 ),
73 'where_arglist' => array
74 (
75 array ('url_argname' => 'port_id', 'table_colname' => 'id', 'assertion' => 'uint'),
76 array ('url_argname' => 'object_id', 'assertion' => 'uint'), # preserve context
77 ),
78 );
79 $opspec_list['object-ports-delPort'] = array
80 (
81 'table' => 'Port',
82 'action' => 'DELETE',
83 'arglist' => array
84 (
85 array ('url_argname' => 'port_id', 'table_colname' => 'id', 'assertion' => 'uint'),
86 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
87 ),
88 );
89 $opspec_list['object-ports-deleteAll'] = array
90 (
91 'table' => 'Port',
92 'action' => 'DELETE',
93 'arglist' => array
94 (
95 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
96 ),
97 );
98 $opspec_list['location-log-del'] = array
99 (
100 'table' => 'ObjectLog',
101 'action' => 'DELETE',
102 'arglist' => array
103 (
104 array ('url_argname' => 'log_id', 'table_colname' => 'id', 'assertion' => 'uint'),
105 array ('url_argname' => 'location_id', 'table_colname' => 'object_id', 'assertion' => 'uint'),
106 ),
107 );
108 $opspec_list['object-log-del'] = array
109 (
110 'table' => 'ObjectLog',
111 'action' => 'DELETE',
112 'arglist' => array
113 (
114 array ('url_argname' => 'log_id', 'table_colname' => 'id', 'assertion' => 'uint'),
115 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
116 ),
117 );
118 $opspec_list['rack-log-del'] = array
119 (
120 'table' => 'ObjectLog',
121 'action' => 'DELETE',
122 'arglist' => array
123 (
124 array ('url_argname' => 'log_id', 'table_colname' => 'id', 'assertion' => 'uint'),
125 array ('url_argname' => 'rack_id', 'table_colname' => 'object_id', 'assertion' => 'uint'),
126 ),
127 );
128 $opspec_list['row-log-del'] = array
129 (
130 'table' => 'ObjectLog',
131 'action' => 'DELETE',
132 'arglist' => array
133 (
134 array ('url_argname' => 'log_id', 'table_colname' => 'id', 'assertion' => 'uint'),
135 array ('url_argname' => 'row_id', 'table_colname' => 'object_id', 'assertion' => 'uint'),
136 ),
137 );
138 $opspec_list['ipv4vs-editlblist-delLB'] =
139 $opspec_list['ipv4rspool-editlblist-delLB'] =
140 $opspec_list['object-editrspvs-delLB'] = array
141 (
142 'table' => 'IPv4LB',
143 'action' => 'DELETE',
144 'arglist' => array
145 (
146 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
147 array ('url_argname' => 'pool_id', 'table_colname' => 'rspool_id', 'assertion' => 'uint'),
148 array ('url_argname' => 'vs_id', 'assertion' => 'uint'),
149 ),
150 );
151 $opspec_list['ipv4vs-editlblist-updLB'] =
152 $opspec_list['ipv4rspool-editlblist-updLB'] =
153 $opspec_list['object-editrspvs-updLB'] = array
154 (
155 'table' => 'IPv4LB',
156 'action' => 'UPDATE',
157 'set_arglist' => array
158 (
159 array ('url_argname' => 'vsconfig', 'assertion' => 'string0', 'translator' => 'nullIfEmptyStr'),
160 array ('url_argname' => 'rsconfig', 'assertion' => 'string0', 'translator' => 'nullIfEmptyStr'),
161 array ('url_argname' => 'prio', 'assertion' => 'string0', 'translator' => 'nullIfEmptyStr'),
162 ),
163 'where_arglist' => array
164 (
165 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
166 array ('url_argname' => 'pool_id', 'table_colname' => 'rspool_id', 'assertion' => 'uint'),
167 array ('url_argname' => 'vs_id', 'assertion' => 'uint'),
168 ),
169 );
170 $opspec_list['object-cacti-add'] = array
171 (
172 'table' => 'CactiGraph',
173 'action' => 'INSERT',
174 'arglist' => array
175 (
176 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
177 array ('url_argname' => 'server_id', 'assertion' => 'uint'),
178 array ('url_argname' => 'graph_id', 'assertion' => 'uint'),
179 array ('url_argname' => 'caption', 'assertion' => 'string0'),
180 ),
181 );
182 $opspec_list['object-cacti-del'] = array
183 (
184 'table' => 'CactiGraph',
185 'action' => 'DELETE',
186 'arglist' => array
187 (
188 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
189 array ('url_argname' => 'server_id', 'assertion' => 'uint'),
190 array ('url_argname' => 'graph_id', 'assertion' => 'uint'),
191 ),
192 );
193 $opspec_list['object-munin-add'] = array
194 (
195 'table' => 'MuninGraph',
196 'action' => 'INSERT',
197 'arglist' => array
198 (
199 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
200 array ('url_argname' => 'server_id', 'assertion' => 'uint'),
201 array ('url_argname' => 'graph', 'assertion' => 'string'),
202 array ('url_argname' => 'caption', 'assertion' => 'string0'),
203 ),
204 );
205 $opspec_list['object-munin-del'] = array
206 (
207 'table' => 'MuninGraph',
208 'action' => 'DELETE',
209 'arglist' => array
210 (
211 array ('url_argname' => 'object_id', 'assertion' => 'uint'),
212 array ('url_argname' => 'server_id', 'assertion' => 'uint'),
213 array ('url_argname' => 'graph', 'assertion' => 'string'),
214 ),
215 );
216 $opspec_list['ipv4rspool-editrslist-delRS'] = array
217 (
218 'table' => 'IPv4RS',
219 'action' => 'DELETE',
220 'arglist' => array
221 (
222 array ('url_argname' => 'id', 'assertion' => 'uint'),
223 ),
224 );
225 $opspec_list['parentmap-edit-add'] = array
226 (
227 'table' => 'ObjectParentCompat',
228 'action' => 'INSERT',
229 'arglist' => array
230 (
231 array ('url_argname' => 'parent_objtype_id', 'assertion' => 'uint'),
232 array ('url_argname' => 'child_objtype_id', 'assertion' => 'uint'),
233 ),
234 );
235 $opspec_list['parentmap-edit-del'] = array
236 (
237 'table' => 'ObjectParentCompat',
238 'action' => 'DELETE',
239 'arglist' => array
240 (
241 array ('url_argname' => 'parent_objtype_id', 'assertion' => 'uint'),
242 array ('url_argname' => 'child_objtype_id', 'assertion' => 'uint'),
243 ),
244 );
245 $opspec_list['portifcompat-edit-add'] = array
246 (
247 'table' => 'PortInterfaceCompat',
248 'action' => 'INSERT',
249 'arglist' => array
250 (
251 array ('url_argname' => 'iif_id', 'assertion' => 'uint'),
252 array ('url_argname' => 'oif_id', 'assertion' => 'uint'),
253 ),
254 );
255 $opspec_list['portifcompat-edit-del'] = array
256 (
257 'table' => 'PortInterfaceCompat',
258 'action' => 'DELETE',
259 'arglist' => array
260 (
261 array ('url_argname' => 'iif_id', 'assertion' => 'uint'),
262 array ('url_argname' => 'oif_id', 'assertion' => 'uint'),
263 ),
264 );
265 $opspec_list['portoifs-edit-add'] = array
266 (
267 'table' => 'PortOuterInterface',
268 'action' => 'INSERT',
269 'arglist' => array
270 (
271 array ('url_argname' => 'oif_name', 'assertion' => 'string'),
272 ),
273 );
274 $opspec_list['portoifs-edit-del'] = array
275 (
276 'table' => 'PortOuterInterface',
277 'action' => 'DELETE',
278 'arglist' => array
279 (
280 array ('url_argname' => 'id', 'assertion' => 'uint'),
281 ),
282 );
283 $opspec_list['portoifs-edit-upd'] = array
284 (
285 'table' => 'PortOuterInterface',
286 'action' => 'UPDATE',
287 'set_arglist' => array
288 (
289 array ('url_argname' => 'oif_name', 'assertion' => 'string'),
290 ),
291 'where_arglist' => array
292 (
293 array ('url_argname' => 'id', 'assertion' => 'uint'),
294 ),
295 );
296 $opspec_list['attrs-editmap-del'] = array
297 (
298 'table' => 'AttributeMap',
299 'action' => 'DELETE',
300 'arglist' => array
301 (
302 array ('url_argname' => 'attr_id', 'assertion' => 'uint'),
303 array ('url_argname' => 'objtype_id', 'assertion' => 'uint'),
304 ),
305 );
306 $opspec_list['attrs-editattrs-add'] = array
307 (
308 'table' => 'Attribute',
309 'action' => 'INSERT',
310 'arglist' => array
311 (
312 array ('url_argname' => 'attr_type', 'table_colname' => 'type', 'assertion' => 'enum/attr_type'),
313 array ('url_argname' => 'attr_name', 'table_colname' => 'name', 'assertion' => 'string'),
314 ),
315 );
316 $opspec_list['attrs-editattrs-del'] = array
317 (
318 'table' => 'Attribute',
319 'action' => 'DELETE',
320 'arglist' => array
321 (
322 array ('url_argname' => 'attr_id', 'table_colname' => 'id', 'assertion' => 'uint'),
323 ),
324 );
325 $opspec_list['attrs-editattrs-upd'] = array
326 (
327 'table' => 'Attribute',
328 'action' => 'UPDATE',
329 'set_arglist' => array
330 (
331 array ('url_argname' => 'attr_name', 'table_colname' => 'name', 'assertion' => 'string'),
332 ),
333 'where_arglist' => array
334 (
335 array ('url_argname' => 'attr_id', 'table_colname' => 'id', 'assertion' => 'uint'),
336 ),
337 );
338 $opspec_list['dict-chapters-add'] = array
339 (
340 'table' => 'Chapter',
341 'action' => 'INSERT',
342 'arglist' => array
343 (
344 array ('url_argname' => 'chapter_name', 'table_colname' => 'name', 'assertion' => 'string')
345 ),
346 );
347 $opspec_list['chapter-edit-add'] = array
348 (
349 'table' => 'Dictionary',
350 'action' => 'INSERT',
351 'arglist' => array
352 (
353 array ('url_argname' => 'chapter_no', 'table_colname' => 'chapter_id', 'assertion' => 'uint'),
354 array ('url_argname' => 'dict_value', 'assertion' => 'string'),
355 ),
356 );
357 $opspec_list['chapter-edit-del'] = array
358 (
359 'table' => 'Dictionary',
360 'action' => 'DELETE',
361 'arglist' => array
362 (
363 // Technically dict_key is enough to delete, but including chapter_id into
364 // WHERE clause makes sure, that the action actually happends for the same
365 // chapter that authorization was granted for.
366 array ('url_argname' => 'chapter_no', 'table_colname' => 'chapter_id', 'assertion' => 'uint'),
367 array ('url_argname' => 'dict_key', 'assertion' => 'uint'),
368 array ('fix_argname' => 'dict_sticky', 'fix_argvalue' => 'no'), # protect system rows
369 ),
370 );
371 $opspec_list['chapter-edit-upd'] = array
372 (
373 'table' => 'Dictionary',
374 'action' => 'UPDATE',
375 'set_arglist' => array
376 (
377 array ('url_argname' => 'dict_value', 'assertion' => 'string'),
378 ),
379 'where_arglist' => array
380 (
381 # same as above for listing chapter_no
382 array ('url_argname' => 'chapter_no', 'table_colname' => 'chapter_id', 'assertion' => 'uint'),
383 array ('url_argname' => 'dict_key', 'assertion' => 'uint'),
384 array ('fix_argname' => 'dict_sticky', 'fix_argvalue' => 'no'), # protect system rows
385 ),
386 );
387 $opspec_list['tagtree-edit-createTag'] = array
388 (
389 'table' => 'TagTree',
390 'action' => 'INSERT',
391 'arglist' => array
392 (
393 array ('url_argname' => 'tag_name', 'table_colname' => 'tag', 'assertion' => 'tag'),
394 array ('url_argname' => 'parent_id', 'assertion' => 'uint0', 'translator' => 'nullIfZero'),
395 array ('url_argname' => 'is_assignable', 'assertion' => 'enum/yesno'),
396 ),
397 );
398 $opspec_list['tagtree-edit-destroyTag'] = array
399 (
400 'table' => 'TagTree',
401 'action' => 'DELETE',
402 'arglist' => array
403 (
404 array ('url_argname' => 'tag_id', 'table_colname' => 'id', 'assertion' => 'uint'),
405 ),
406 );
407 $opspec_list['8021q-vstlist-add'] = array
408 (
409 'table' => 'VLANSwitchTemplate',
410 'action' => 'INSERT',
411 'arglist' => array
412 (
413 array ('url_argname' => 'vst_descr', 'table_colname' => 'description', 'assertion' => 'string'),
414 // workaround SQL_STRICT
415 array ('fix_argname' => 'mutex_rev', 'fix_argvalue' => 0),
416 array ('fix_argname' => 'saved_by', 'fix_argvalue' => ""),
417 ),
418 );
419 $opspec_list['8021q-vstlist-del'] = array
420 (
421 'table' => 'VLANSwitchTemplate',
422 'action' => 'DELETE',
423 'arglist' => array
424 (
425 array ('url_argname' => 'vst_id', 'table_colname' => 'id', 'assertion' => 'uint'),
426 ),
427 );
428 $opspec_list['8021q-vstlist-upd'] = array
429 (
430 'table' => 'VLANSwitchTemplate',
431 'action' => 'UPDATE',
432 'set_arglist' => array
433 (
434 array ('url_argname' => 'vst_descr', 'table_colname' => 'description', 'assertion' => 'string'),
435 ),
436 'where_arglist' => array
437 (
438 array ('url_argname' => 'vst_id', 'table_colname' => 'id', 'assertion' => 'uint'),
439 ),
440 );
441 $opspec_list['8021q-vdlist-del'] = array
442 (
443 'table' => 'VLANDomain',
444 'action' => 'DELETE',
445 'arglist' => array
446 (
447 array ('url_argname' => 'vdom_id', 'table_colname' => 'id', 'assertion' => 'uint'),
448 ),
449 );
450 $opspec_list['vlandomain-vlanlist-add'] = array
451 (
452 'table' => 'VLANDescription',
453 'action' => 'INSERT',
454 'arglist' => array
455 (
456 array ('url_argname' => 'vdom_id', 'table_colname' => 'domain_id', 'assertion' => 'uint'),
457 array ('url_argname' => 'vlan_id', 'assertion' => 'vlan'),
458 array ('url_argname' => 'vlan_type', 'assertion' => 'enum/vlan_type'),
459 array ('url_argname' => 'vlan_descr', 'assertion' => 'string0', 'translator' => 'nullIfEmptyStr'),
460 ),
461 );
462 $opspec_list['vlandomain-vlanlist-del'] = array
463 (
464 'table' => 'VLANDescription',
465 'action' => 'DELETE',
466 'arglist' => array
467 (
468 array ('url_argname' => 'vdom_id', 'table_colname' => 'domain_id', 'assertion' => 'uint'),
469 array ('url_argname' => 'vlan_id', 'assertion' => 'vlan'),
470 ),
471 );
472 $opspec_list['vlan-edit-upd'] = // both locations are using the same tableHandler op
473 $opspec_list['vlandomain-vlanlist-upd'] = array
474 (
475 'table' => 'VLANDescription',
476 'action' => 'UPDATE',
477 'set_arglist' => array
478 (
479 array ('url_argname' => 'vlan_type', 'assertion' => 'enum/vlan_type'),
480 array ('url_argname' => 'vlan_descr', 'assertion' => 'string0', 'translator' => 'nullIfEmptyStr'),
481 ),
482 'where_arglist' => array
483 (
484 array ('url_argname' => 'vdom_id', 'table_colname' => 'domain_id', 'assertion' => 'uint'),
485 array ('url_argname' => 'vlan_id', 'assertion' => 'vlan'),
486 ),
487 );
488 $opspec_list['dict-chapters-upd'] = array
489 (
490 'table' => 'Chapter',
491 'action' => 'UPDATE',
492 'set_arglist' => array
493 (
494 array ('url_argname' => 'chapter_name', 'table_colname' => 'name', 'assertion' => 'string'),
495 ),
496 'where_arglist' => array
497 (
498 array ('url_argname' => 'chapter_no', 'table_colname' => 'id', 'assertion' => 'uint'),
499 array ('fix_argname' => 'sticky', 'fix_argvalue' => 'no'), # protect system chapters
500 ),
501 );
502 $opspec_list['dict-chapters-del'] = array
503 (
504 'table' => 'Chapter',
505 'action' => 'DELETE',
506 'arglist' => array
507 (
508 array ('url_argname' => 'chapter_no', 'table_colname' => 'id', 'assertion' => 'uint'),
509 array ('fix_argname' => 'sticky', 'fix_argvalue' => 'no'), # protect system chapters
510 ),
511 );
512 $opspec_list['cacti-servers-add'] = array
513 (
514 'table' => 'CactiServer',
515 'action' => 'INSERT',
516 'arglist' => array
517 (
518 array ('url_argname' => 'base_url', 'assertion' => 'string'),
519 array ('url_argname' => 'username', 'assertion' => 'string0'),
520 array ('url_argname' => 'password', 'assertion' => 'string0'),
521 ),
522 );
523 $opspec_list['cacti-servers-del'] = array
524 (
525 'table' => 'CactiServer',
526 'action' => 'DELETE',
527 'arglist' => array
528 (
529 array ('url_argname' => 'id', 'assertion' => 'uint'),
530 ),
531 );
532 $opspec_list['cacti-servers-upd'] = array
533 (
534 'table' => 'CactiServer',
535 'action' => 'UPDATE',
536 'set_arglist' => array
537 (
538 array ('url_argname' => 'base_url', 'assertion' => 'string'),
539 array ('url_argname' => 'username', 'assertion' => 'string0'),
540 array ('url_argname' => 'password', 'assertion' => 'string0'),
541 ),
542 'where_arglist' => array
543 (
544 array ('url_argname' => 'id', 'assertion' => 'uint'),
545 ),
546 );
547 $opspec_list['munin-servers-add'] = array
548 (
549 'table' => 'MuninServer',
550 'action' => 'INSERT',
551 'arglist' => array
552 (
553 array ('url_argname' => 'base_url', 'assertion' => 'string')
554 ),
555 );
556 $opspec_list['munin-servers-del'] = array
557 (
558 'table' => 'MuninServer',
559 'action' => 'DELETE',
560 'arglist' => array
561 (
562 array ('url_argname' => 'id', 'assertion' => 'uint'),
563 ),
564 );
565 $opspec_list['munin-servers-upd'] = array
566 (
567 'table' => 'MuninServer',
568 'action' => 'UPDATE',
569 'set_arglist' => array
570 (
571 array ('url_argname' => 'base_url', 'assertion' => 'string'),
572 ),
573 'where_arglist' => array
574 (
575 array ('url_argname' => 'id', 'assertion' => 'uint'),
576 ),
577 );
578 $opspec_list['cables-heaps-add'] = array
579 (
580 'table' => 'PatchCableHeap',
581 'action' => 'INSERT',
582 'arglist' => array
583 (
584 array ('url_argname' => 'end1_conn_id', 'assertion' => 'uint'),
585 array ('url_argname' => 'pctype_id', 'assertion' => 'uint'),
586 array ('url_argname' => 'end2_conn_id', 'assertion' => 'uint'),
587 array ('fix_argname' => 'amount', 'fix_argvalue' => 0),
588 array ('url_argname' => 'length', 'assertion' => 'decimal'),
589 array ('url_argname' => 'description', 'assertion' => 'string0'),
590 ),
591 );
592 $opspec_list['cables-heaps-del'] = array
593 (
594 'table' => 'PatchCableHeap',
595 'action' => 'DELETE',
596 'arglist' => array
597 (
598 array ('url_argname' => 'id', 'assertion' => 'uint'),
599 ),
600 );
601 $opspec_list['cables-heaps-upd'] = array
602 (
603 'table' => 'PatchCableHeap',
604 'action' => 'UPDATE',
605 'set_arglist' => array
606 (
607 array ('url_argname' => 'end1_conn_id', 'assertion' => 'uint'),
608 array ('url_argname' => 'pctype_id', 'assertion' => 'uint'),
609 array ('url_argname' => 'end2_conn_id', 'assertion' => 'uint'),
610 array ('url_argname' => 'length', 'assertion' => 'decimal'),
611 array ('url_argname' => 'description', 'assertion' => 'string0'),
612 ),
613 'where_arglist' => array
614 (
615 array ('url_argname' => 'id', 'assertion' => 'uint'),
616 ),
617 );
618 $opspec_list['cableconf-connectors-add'] = array
619 (
620 'table' => 'PatchCableConnector',
621 'action' => 'INSERT',
622 'arglist' => array
623 (
624 array ('url_argname' => 'connector', 'assertion' => 'string'),
625 array ('fix_argname' => 'origin', 'fix_argvalue' => 'custom'),
626 ),
627 );
628 $opspec_list['cableconf-connectors-del'] = array
629 (
630 'table' => 'PatchCableConnector',
631 'action' => 'DELETE',
632 'arglist' => array
633 (
634 array ('url_argname' => 'id', 'assertion' => 'uint'),
635 array ('fix_argname' => 'origin', 'fix_argvalue' => 'custom'),
636 ),
637 );
638 $opspec_list['cableconf-connectors-upd'] = array
639 (
640 'table' => 'PatchCableConnector',
641 'action' => 'UPDATE',
642 'set_arglist' => array
643 (
644 array ('url_argname' => 'connector', 'assertion' => 'string'),
645 ),
646 'where_arglist' => array
647 (
648 array ('url_argname' => 'id', 'assertion' => 'uint'),
649 array ('fix_argname' => 'origin', 'fix_argvalue' => 'custom'),
650 ),
651 );
652 $opspec_list['cableconf-cabletypes-add'] = array
653 (
654 'table' => 'PatchCableType',
655 'action' => 'INSERT',
656 'arglist' => array
657 (
658 array ('url_argname' => 'pctype', 'assertion' => 'string'),
659 array ('fix_argname' => 'origin', 'fix_argvalue' => 'custom'),
660 ),
661 );
662 $opspec_list['cableconf-cabletypes-del'] = array
663 (
664 'table' => 'PatchCableType',
665 'action' => 'DELETE',
666 'arglist' => array
667 (
668 array ('url_argname' => 'id', 'assertion' => 'uint'),
669 array ('fix_argname' => 'origin', 'fix_argvalue' => 'custom'),
670 ),
671 );
672 $opspec_list['cableconf-cabletypes-upd'] = array
673 (
674 'table' => 'PatchCableType',
675 'action' => 'UPDATE',
676 'set_arglist' => array
677 (
678 array ('url_argname' => 'pctype', 'assertion' => 'string'),
679 ),
680 'where_arglist' => array
681 (
682 array ('url_argname' => 'id', 'assertion' => 'uint'),
683 array ('fix_argname' => 'origin', 'fix_argvalue' => 'custom'),
684 ),
685 );
686 $opspec_list['cableconf-conncompat-add'] = array
687 (
688 'table' => 'PatchCableConnectorCompat',
689 'action' => 'INSERT',
690 'arglist' => array
691 (
692 array ('url_argname' => 'pctype_id', 'assertion' => 'uint'),
693 array ('url_argname' => 'connector_id', 'assertion' => 'uint'),
694 ),
695 );
696 $opspec_list['cableconf-conncompat-del'] = array
697 (
698 'table' => 'PatchCableConnectorCompat',
699 'action' => 'DELETE',
700 'arglist' => array
701 (
702 array ('url_argname' => 'pctype_id', 'assertion' => 'uint'),
703 array ('url_argname' => 'connector_id', 'assertion' => 'uint'),
704 ),
705 );
706 $opspec_list['cableconf-oifcompat-add'] = array
707 (
708 'table' => 'PatchCableOIFCompat',
709 'action' => 'INSERT',
710 'arglist' => array
711 (
712 array ('url_argname' => 'pctype_id', 'assertion' => 'uint'),
713 array ('url_argname' => 'oif_id', 'assertion' => 'uint'),
714 ),
715 );
716 $opspec_list['cableconf-oifcompat-del'] = array
717 (
718 'table' => 'PatchCableOIFCompat',
719 'action' => 'DELETE',
720 'arglist' => array
721 (
722 array ('url_argname' => 'pctype_id', 'assertion' => 'uint'),
723 array ('url_argname' => 'oif_id', 'assertion' => 'uint'),
724 ),
725 );
726
727 function setFuncMessages ($funcname, $messages)
728 {
729 global $msgcode;
730 foreach ($messages as $symbol => $code)
731 $msgcode[$funcname][$symbol] = $code;
732 }
733
734 function addPortForwarding ()
735 {
736 setFuncMessages (__FUNCTION__, array ('OK' => 48));
737 $proto = genericAssertion ('proto', 'enum/natv4proto');
738 if ($proto != 'ALL')
739 {
740 assertUIntArg ('localport');
741 assertUIntArg ('remoteport');
742 }
743 assertStringArg ('description', TRUE);
744 $remoteport = isset ($_REQUEST['remoteport']) ? $_REQUEST['remoteport'] : '';
745 if ($remoteport == '')
746 $remoteport = $_REQUEST['localport'];
747
748 try
749 {
750 newPortForwarding
751 (
752 getBypassValue(),
753 genericAssertion ('localip', 'inet4'),
754 $_REQUEST['localport'],
755 genericAssertion ('remoteip', 'inet4'),
756 $remoteport,
757 $proto,
758 $_REQUEST['description']
759 );
760 }
761 catch (InvalidArgException $iae)
762 {
763 throw $iae->newIRAE();
764 }
765 showFuncMessage (__FUNCTION__, 'OK');
766 }
767
768 function delPortForwarding ()
769 {
770 setFuncMessages (__FUNCTION__, array ('OK' => 49));
771 $proto = genericAssertion ('proto', 'enum/natv4proto');
772 if ($proto != 'ALL')
773 {
774 assertUIntArg ('localport');
775 assertUIntArg ('remoteport');
776 }
777
778 deletePortForwarding
779 (
780 getBypassValue(),
781 genericAssertion ('localip', 'inet4'),
782 $_REQUEST['localport'],
783 genericAssertion ('remoteip', 'inet4'),
784 $_REQUEST['remoteport'],
785 $proto
786 );
787 showFuncMessage (__FUNCTION__, 'OK');
788 }
789
790 function updPortForwarding ()
791 {
792 setFuncMessages (__FUNCTION__, array ('OK' => 51));
793 $proto = genericAssertion ('proto', 'enum/natv4proto');
794 if ($proto != 'ALL')
795 {
796 assertUIntArg ('localport');
797 assertUIntArg ('remoteport');
798 }
799 assertStringArg ('description', TRUE);
800
801 updatePortForwarding
802 (
803 getBypassValue(),
804 genericAssertion ('localip', 'inet4'),
805 $_REQUEST['localport'],
806 genericAssertion ('remoteip', 'inet4'),
807 $_REQUEST['remoteport'],
808 $proto,
809 $_REQUEST['description']
810 );
811 showFuncMessage (__FUNCTION__, 'OK');
812 }
813
814 function addPortForObject ()
815 {
816 setFuncMessages (__FUNCTION__, array ('OK' => 48));
817 genericAssertion ('port_name', 'string');
818 try
819 {
820 commitAddPort
821 (
822 getBypassValue(),
823 trim ($_REQUEST['port_name']),
824 genericAssertion ('port_type_id', 'string'),
825 trim ($_REQUEST['port_label']),
826 trim (genericAssertion ('port_l2address', 'l2address0'))
827 );
828 }
829 catch (InvalidRequestArgException $irae)
830 {
831 throw $irae;
832 }
833 catch (InvalidArgException $iae)
834 {
835 throw $iae->newIRAE();
836 }
837 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['port_name']));
838 }
839
840 function editPortForObject ()
841 {
842 setFuncMessages (__FUNCTION__, array ('OK' => 6));
843 global $sic;
844 $port_id = assertUIntArg ('port_id');
845 try
846 {
847 commitUpdatePort
848 (
849 getBypassValue(),
850 $port_id,
851 genericAssertion ('name', 'string'),
852 assertStringArg ('port_type_id'),
853 genericAssertion ('label', 'string0'),
854 genericAssertion ('l2address', 'l2address0'),
855 assertStringArg ('reservation_comment', TRUE)
856 );
857 }
858 catch (InvalidRequestArgException $irae)
859 {
860 throw $irae;
861 }
862 catch (InvalidArgException $iae)
863 {
864 throw $iae->newIRAE();
865 }
866 if (array_key_exists ('cable', $_REQUEST))
867 commitUpdatePortLink ($port_id, $sic['cable']);
868 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
869 }
870
871 function addMultiPorts ()
872 {
873 setFuncMessages (__FUNCTION__, array ('OK' => 10));
874 assertStringArg ('input');
875 $format = genericAssertion ('format', 'string');
876 $port_type = genericAssertion ('port_type', 'string');
877 $object_id = getBypassValue();
878 $ports = array();
879 foreach (textareaCooked ($_REQUEST['input']) as $line)
880 {
881 switch ($format)
882 {
883 case 'ssv1':
884 $words = explode (' ', $line);
885 if ($words[0] == '') // empty L2 address is OK
886 continue;
887 $ports[] = array
888 (
889 'name' => $words[0],
890 'l2address' => array_fetch ($words, 1, ''),
891 'label' => ''
892 );
893 break;
894 default:
895 throw new RackTablesError ("unknown data format '${format}'", RackTablesError::INTERNAL);
896 }
897 }
898 // Create ports, if they don't exist.
899 $added_count = $updated_count = $error_count = 0;
900 foreach ($ports as $port)
901 {
902 $port_ids = getPortIDs ($object_id, $port['name']);
903 try
904 {
905 if (!count ($port_ids))
906 {
907 commitAddPort ($object_id, $port['name'], $port_type, $port['label'], $port['l2address']);
908 $added_count++;
909 }
910 elseif (count ($port_ids) == 1) // update only single-socket ports
911 {
912 $rsvc = getPortReservationComment (array_first ($port_ids));
913 commitUpdatePort ($object_id, $port_ids[0], $port['name'], $port_type, $port['label'], $port['l2address'], $rsvc);
914 $updated_count++;
915 }
916 }
917 catch (InvalidArgException $iae)
918 {
919 showError ($iae->getMessage());
920 }
921 }
922 showFuncMessage (__FUNCTION__, 'OK', array ($added_count, $updated_count, $error_count));
923 }
924
925 function addBulkPorts ()
926 {
927 setFuncMessages (__FUNCTION__, array ('OK' => 82));
928 assertStringArg ('port_name', TRUE);
929 assertStringArg ('port_label', TRUE);
930
931 $object_id = getBypassValue();
932 $port_name = $_REQUEST['port_name'];
933 $port_type_id = genericAssertion ('port_type_id', 'string');
934 $port_label = $_REQUEST['port_label'];
935 $port_numbering_start = genericAssertion ('port_numbering_start', 'uint0');
936 $port_numbering_count = genericAssertion ('port_numbering_count', 'uint');
937
938 $added_count = $error_count = 0;
939 if (strrpos ($port_name, '%u') === FALSE)
940 $port_name .= '%u';
941 if (strrpos ($port_label, '%u') === FALSE)
942 $port_label .= '%u';
943 for ($i = 0, $c = $port_numbering_start; $i < $port_numbering_count; $i++, $c++)
944 {
945 commitAddPort ($object_id, @sprintf ($port_name, $c), $port_type_id, @sprintf ($port_label, $c), '');
946 $added_count++;
947 }
948 showFuncMessage (__FUNCTION__, 'OK', array ($added_count, $error_count));
949 }
950
951 function updIPAllocation ()
952 {
953 setFuncMessages (__FUNCTION__, array ('OK' => 51));
954 $ip_bin = assertIPArg ('ip');
955 assertStringArg ('bond_name', TRUE);
956 updateIPBond
957 (
958 $ip_bin,
959 genericAssertion ('object_id', 'uint'),
960 $_REQUEST['bond_name'],
961 genericAssertion ('bond_type', 'enum/alloc_type')
962 );
963 showFuncMessage (__FUNCTION__, 'OK');
964 return buildRedirectURL (NULL, NULL, array ('hl_ip' => ip_format ($ip_bin)));
965 }
966
967 function delIPAllocation ()
968 {
969 setFuncMessages (__FUNCTION__, array ('OK' => 49));
970 unbindIPFromObject (genericAssertion ('ip', 'inet'), genericAssertion ('object_id', 'uint'));
971 showFuncMessage (__FUNCTION__, 'OK');
972 }
973
974 function addIPAllocation ()
975 {
976 setFuncMessages (__FUNCTION__, array ('OK' => 48, 'ERR1' => 170));
977 $ip_bin = assertIPArg ('ip');
978 $alloc_type = genericAssertion ('bond_type', 'enum/alloc_type');
979
980 // check if address is alread allocated
981 $address = getIPAddress($ip_bin);
982
983 if(!empty($address['allocs']) && ( ($address['allocs'][0]['type'] != 'shared') || ($alloc_type != 'shared') ) )
984 showWarning("IP ".ip_format($ip_bin)." already in use by ".$address['allocs'][0]['object_name']." - ".$address['allocs'][0]['name']);
985
986 if (getConfigVar ('IPV4_JAYWALK') != 'yes' && NULL === getIPAddressNetworkId ($ip_bin))
987 {
988 showFuncMessage (__FUNCTION__, 'ERR1', array (ip_format ($ip_bin)));
989 return;
990 }
991
992 if($address['reserved'] && $address['name'] != '')
993 {
994 showWarning("IP ".ip_format($ip_bin)." reservation \"".$address['name']."\" is removed");
995 //TODO ask to take reserved IP or not !
996 }
997
998 bindIPToObject
999 (
1000 $ip_bin,
1001 genericAssertion ('object_id', 'uint'),
1002 genericAssertion ('bond_name', 'string0'),
1003 $alloc_type
1004 );
1005
1006 showFuncMessage (__FUNCTION__, 'OK');
1007 return buildRedirectURL (NULL, NULL, array ('hl_ip' => ip_format ($ip_bin)));
1008 }
1009
1010 function addIPv4Prefix ()
1011 {
1012 global $sic;
1013 $vlan_ck = empty ($sic['vlan_ck']) ? NULL : genericAssertion ('vlan_ck', 'uint-vlan1');
1014 $net_id = createIPv4Prefix
1015 (
1016 genericAssertion ('range', 'string'),
1017 genericAssertion ('name', 'string0'),
1018 isCheckSet ('is_connected'),
1019 genericAssertion ('taglist', 'array0')
1020 );
1021 $net_cell = spotEntity ('ipv4net', $net_id);
1022 if (isset ($vlan_ck))
1023 {
1024 if (considerConfiguredConstraint ($net_cell, 'VLANIPV4NET_LISTSRC'))
1025 commitSupplementVLANIPv4 ($vlan_ck, $net_id);
1026 else
1027 showError ("VLAN binding to network " . mkCellA ($net_cell) . " is restricted in config");
1028 }
1029 showSuccess ('IP network ' . mkCellA ($net_cell) . ' has been created');
1030 }
1031
1032 function addIPv6Prefix ()
1033 {
1034 global $sic;
1035 $vlan_ck = empty ($sic['vlan_ck']) ? NULL : genericAssertion ('vlan_ck', 'uint-vlan1');
1036 $net_id = createIPv6Prefix
1037 (
1038 genericAssertion ('range', 'string'),
1039 genericAssertion ('name', 'string0'),
1040 isCheckSet ('is_connected'),
1041 genericAssertion ('taglist', 'array0')
1042 );
1043 $net_cell = spotEntity ('ipv6net', $net_id);
1044 if (isset ($vlan_ck))
1045 {
1046 if (considerConfiguredConstraint ($net_cell, 'VLANIPV4NET_LISTSRC'))
1047 commitSupplementVLANIPv6 ($vlan_ck, $net_id);
1048 else
1049 showError ("VLAN binding to network " . mkCellA ($net_cell) . " is restricted in config");
1050 }
1051 showSuccess ('IP network ' . mkCellA ($net_cell) . ' has been created');
1052 }
1053
1054 function delIPv4Prefix ()
1055 {
1056 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1057 $netinfo = spotEntity ('ipv4net', genericAssertion ('id', 'uint'));
1058 loadIPAddrList ($netinfo);
1059 if (! isIPNetworkEmpty ($netinfo))
1060 {
1061 showError ("There are allocations within prefix, delete forbidden");
1062 return;
1063 }
1064 if (array_key_exists ($netinfo['ip_bin'], $netinfo['addrlist']))
1065 updateV4Address ($netinfo['ip_bin'], '', 'no');
1066 $last_ip = ip_last ($netinfo);
1067 if (array_key_exists ($last_ip, $netinfo['addrlist']))
1068 updateV4Address ($last_ip, '', 'no');
1069 destroyIPv4Prefix ($netinfo['id']);
1070 showFuncMessage (__FUNCTION__, 'OK');
1071 global $pageno;
1072 if ($pageno == 'ipv4net')
1073 return buildRedirectURL ('index', 'default');
1074 }
1075
1076 function delIPv6Prefix ()
1077 {
1078 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1079 $netinfo = spotEntity ('ipv6net', genericAssertion ('id', 'uint'));
1080 loadIPAddrList ($netinfo);
1081 if (! isIPNetworkEmpty ($netinfo))
1082 {
1083 showError ("There are allocations within prefix, delete forbidden");
1084 return;
1085 }
1086 if (array_key_exists ($netinfo['ip_bin'], $netinfo['addrlist']))
1087 updateV6Address ($netinfo['ip_bin'], '', 'no');
1088 destroyIPv6Prefix ($netinfo['id']);
1089 showFuncMessage (__FUNCTION__, 'OK');
1090 global $pageno;
1091 if ($pageno == 'ipv6net')
1092 return buildRedirectURL ('index', 'default');
1093 }
1094
1095 function editAddress ()
1096 {
1097 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1098 assertStringArg ('name', TRUE);
1099 assertStringArg ('comment', TRUE);
1100 updateAddress
1101 (
1102 genericAssertion ('ip', 'inet'),
1103 $_REQUEST['name'],
1104 isCheckSet ('reserved', 'yesno'),
1105 $_REQUEST['comment']
1106 );
1107 showFuncMessage (__FUNCTION__, 'OK');
1108 }
1109
1110 function createUser ()
1111 {
1112 setFuncMessages (__FUNCTION__, array ('OK' => 5));
1113 assertStringArg ('username');
1114 assertStringArg ('realname', TRUE);
1115 assertStringArg ('password');
1116 $username = $_REQUEST['username'];
1117 $password = sha1 ($_REQUEST['password']);
1118 $user_id = commitCreateUserAccount ($username, $_REQUEST['realname'], $password);
1119 if (isset ($_REQUEST['taglist']))
1120 produceTagsForNewRecord ('user', $_REQUEST['taglist'], $user_id);
1121 showFuncMessage (__FUNCTION__, 'OK', array ($username));
1122 }
1123
1124 function updateUser ()
1125 {
1126 setFuncMessages (__FUNCTION__, array ('OK' => 6));
1127 $user_id = genericAssertion ('user_id', 'uint');
1128 $username = assertStringArg ('username');
1129 assertStringArg ('realname', TRUE);
1130 $new_password = assertStringArg ('password', TRUE);
1131 $userinfo = spotEntity ('user', $user_id);
1132 // Set new password only if provided.
1133 $new_password = $new_password != '' ? sha1 ($new_password) : $userinfo['user_password_hash'];
1134 commitUpdateUserAccount ($user_id, $username, $_REQUEST['realname'], $new_password);
1135 // if user account renaming is being performed, change key value in UserConfig table
1136 if ($userinfo['user_name'] !== $username)
1137 usePreparedUpdateBlade ('UserConfig', array ('user' => $username), array('user' => $userinfo['user_name']));
1138 showFuncMessage (__FUNCTION__, 'OK', array ($username));
1139 }
1140
1141 function supplementAttrMap ()
1142 {
1143 setFuncMessages (__FUNCTION__, array ('OK' => 48, 'ERR1' => 154));
1144 $attr_id = assertUIntArg ('attr_id');
1145 if (getAttrType ($attr_id) != 'dict')
1146 $chapter_id = NULL;
1147 else
1148 {
1149 try
1150 {
1151 $chapter_id = genericAssertion ('chapter_no', 'uint');
1152 }
1153 catch (InvalidRequestArgException $e)
1154 {
1155 showFuncMessage (__FUNCTION__, 'ERR1', array ('chapter not selected'));
1156 return;
1157 }
1158 }
1159 commitSupplementAttrMap ($attr_id, genericAssertion ('objtype_id', 'uint'), $chapter_id);
1160 showFuncMessage (__FUNCTION__, 'OK');
1161 }
1162
1163 function clearSticker ()
1164 {
1165 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1166 $attr_id = assertUIntArg ('attr_id');
1167 if (permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $attr_id))))
1168 commitUpdateAttrValue (getBypassValue(), $attr_id);
1169 else
1170 {
1171 $oldvalues = getAttrValues (getBypassValue());
1172 showError ('Permission denied, "' . $oldvalues[$attr_id]['name'] . '" left unchanged');
1173 }
1174 }
1175
1176 // This function accepts rack data returned by amplifyCell(), validates and applies changes
1177 // supplied in $_REQUEST and returns resulting array. Only those changes are examined that
1178 // correspond to current rack ID.
1179 // 1st arg is rackdata, 2nd arg is unchecked state, 3rd arg is checked state.
1180 // If 4th arg is present, object_id fields will be updated accordingly to the new state.
1181 // The function returns TRUE if the DB was successfully changed, FALSE otherwise
1182 function processGridForm (&$rackData, $unchecked_state, $checked_state, $object_id = 0)
1183 {
1184 global $loclist, $dbxlink;
1185 $rack_id = $rackData['id'];
1186 $rack_name = $rackData['name'];
1187 $rackchanged = FALSE;
1188 $dbxlink->beginTransaction();
1189 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
1190 {
1191 for ($locidx = 0; $locidx < 3; $locidx++)
1192 {
1193 if ($rackData[$unit_no][$locidx]['enabled'] != TRUE)
1194 continue;
1195 // detect a change
1196 $state = $rackData[$unit_no][$locidx]['state'];
1197 $newstate = isCheckSet ("atom_${rack_id}_${unit_no}_${locidx}") ? $checked_state : $unchecked_state;
1198 if ($state == $newstate)
1199 continue;
1200 $rackchanged = TRUE;
1201 // and validate
1202 $atom = $loclist[$locidx];
1203 // The only changes allowed are those introduced by checkbox grid.
1204 if
1205 (
1206 !($state == $checked_state && $newstate == $unchecked_state) &&
1207 !($state == $unchecked_state && $newstate == $checked_state)
1208 )
1209 {
1210 showError ("${rack_name}: Rack ID ${rack_id}, unit ${unit_no}, 'atom ${atom}', cannot change state from '${state}' to '${newstate}'");
1211 $dbxlink->rollBack();
1212 return FALSE;
1213 }
1214 // Here we avoid using ON DUPLICATE KEY UPDATE by first performing DELETE
1215 // anyway and then looking for probable need of INSERT.
1216 usePreparedDeleteBlade ('RackSpace', array ('rack_id' => $rack_id, 'unit_no' => $unit_no, 'atom' => $atom));
1217 if ($newstate != 'F')
1218 usePreparedInsertBlade ('RackSpace', array ('rack_id' => $rack_id, 'unit_no' => $unit_no, 'atom' => $atom, 'state' => $newstate));
1219 if ($newstate == 'T' && $object_id != 0)
1220 {
1221 // At this point we already have a record in RackSpace.
1222 usePreparedUpdateBlade
1223 (
1224 'RackSpace',
1225 array ('object_id' => $object_id),
1226 array
1227 (
1228 'rack_id' => $rack_id,
1229 'unit_no' => $unit_no,
1230 'atom' => $atom,
1231 )
1232 );
1233 $rackData[$unit_no][$locidx]['object_id'] = $object_id;
1234 }
1235 }
1236 }
1237 if ($rackchanged)
1238 {
1239 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1240 $dbxlink->commit();
1241 return TRUE;
1242 }
1243 $dbxlink->rollBack();
1244 return FALSE;
1245 }
1246
1247 function updateObjectAllocation ()
1248 {
1249 setFuncMessages (__FUNCTION__, array ('OK' => 63));
1250 global $remote_username;
1251 global $op;
1252 if (!isset ($_REQUEST['got_atoms']))
1253 {
1254 unset($_GET['page']);
1255 unset($_GET['tab']);
1256 unset($_GET['op']);
1257 unset($_POST['page']);
1258 unset($_POST['tab']);
1259 unset($_POST['op']);
1260 return buildRedirectURL (NULL, NULL, $_REQUEST);
1261 }
1262 $object_id = getBypassValue();
1263 $object = spotEntity ('object', $object_id);
1264 $changecnt = 0;
1265 // Get a list of rack ids which are parents of the object
1266 $parentRacks = reduceSubarraysToColumn (getParents ($object, 'rack'), 'id');
1267 $workingRacksData = array();
1268 foreach ($_REQUEST['rackmulti'] as $cand_id)
1269 {
1270 if (!isset ($workingRacksData[$cand_id]))
1271 {
1272 $rackData = spotEntity ('rack', $cand_id);
1273 amplifyCell ($rackData);
1274 $workingRacksData[$cand_id] = $rackData;
1275 }
1276 else
1277 $rackData = $workingRacksData[$cand_id];
1278 $is_ro = ! rackModificationPermitted ($rackData, $op, FALSE);
1279 // It's zero-U mounted to this rack on the form, but not in the DB. Mount it.
1280 if (isset($_REQUEST["zerou_${cand_id}"]) && !in_array($cand_id, $parentRacks))
1281 {
1282 if ($is_ro)
1283 continue;
1284 $changecnt++;
1285 commitLinkEntities ('rack', $cand_id, 'object', $object_id);
1286 }
1287 // It's not zero-U mounted to this rack on the form, but it is in the DB. Unmount it.
1288 if (!isset($_REQUEST["zerou_${cand_id}"]) && in_array($cand_id, $parentRacks))
1289 {
1290 if ($is_ro)
1291 continue;
1292 $changecnt++;
1293 commitUnlinkEntities ('rack', $cand_id, 'object', $object_id);
1294 }
1295 }
1296
1297 foreach (array_keys ($workingRacksData) as $key)
1298 applyObjectMountMask ($workingRacksData[$key], $object_id);
1299
1300 $oldMolecule = getMoleculeForObject ($object_id);
1301 foreach ($workingRacksData as $rack_id => $rackData)
1302 {
1303 $is_ro = ! rackModificationPermitted ($rackData, $op, FALSE);
1304 if ($is_ro || !processGridForm ($rackData, 'F', 'T', $object_id))
1305 continue;
1306 $changecnt++;
1307 // Reload our working copy after form processing.
1308 $rackData = spotEntity ('rack', $cand_id);
1309 amplifyCell ($rackData);
1310 applyObjectMountMask ($rackData, $object_id);
1311 $workingRacksData[$rack_id] = $rackData;
1312 }
1313 if ($changecnt)
1314 {
1315 // Log a record.
1316 $newMolecule = getMoleculeForObject ($object_id);
1317 usePreparedInsertBlade
1318 (
1319 'MountOperation',
1320 array
1321 (
1322 'object_id' => $object_id,
1323 'old_molecule_id' => count ($oldMolecule) ? createMolecule ($oldMolecule) : NULL,
1324 'new_molecule_id' => count ($newMolecule) ? createMolecule ($newMolecule) : NULL,
1325 'user_name' => $remote_username,
1326 'comment' => nullIfEmptyStr (genericAssertion ('comment', 'string0')),
1327 )
1328 );
1329 }
1330 showFuncMessage (__FUNCTION__, 'OK', array ($changecnt));
1331 }
1332
1333 function updateObject ()
1334 {
1335 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1336 $taglist = genericAssertion ('taglist', 'array0');
1337 genericAssertion ('num_attrs', 'uint0');
1338 genericAssertion ('object_name', 'string0');
1339 genericAssertion ('object_label', 'string0');
1340 genericAssertion ('object_asset_no', 'string0');
1341 genericAssertion ('object_comment', 'string0');
1342 $object_type_id = genericAssertion ('object_type_id', 'uint');
1343 $object_id = getBypassValue();
1344
1345 global $dbxlink;
1346 $dbxlink->beginTransaction();
1347 commitUpdateObject
1348 (
1349 $object_id,
1350 $_REQUEST['object_name'],
1351 $_REQUEST['object_label'],
1352 isCheckSet ('object_has_problems', 'yesno'),
1353 $_REQUEST['object_asset_no'],
1354 $_REQUEST['object_comment']
1355 );
1356 updateObjectAttributes ($object_id);
1357 $object = spotEntity ('object', $object_id);
1358 if ($object_type_id != $object['objtype_id'])
1359 {
1360 if (! array_key_exists ($object_type_id, getObjectTypeChangeOptions ($object_id)))
1361 throw new InvalidRequestArgException ('new type_id', $object_type_id, 'incompatible with requested attribute values');
1362 usePreparedUpdateBlade ('Object', array ('objtype_id' => $object_type_id), array ('id' => $object_id));
1363 }
1364 // Invalidate thumb cache of all racks objects could occupy.
1365 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1366 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1367 $dbxlink->commit();
1368 rebuildTagChainForEntity ('object', $object_id, buildTagChainFromIds ($taglist), TRUE);
1369 showFuncMessage (__FUNCTION__, 'OK');
1370 }
1371
1372 // Used when updating an object, location or rack
1373 function updateObjectAttributes ($object_id)
1374 {
1375 $type_id = getObjectType ($object_id);
1376 $oldvalues = getAttrValues ($object_id);
1377 $num_attrs = isset ($_REQUEST['num_attrs']) ? $_REQUEST['num_attrs'] : 0;
1378 for ($i = 0; $i < $num_attrs; $i++)
1379 {
1380 $attr_id = genericAssertion ("${i}_attr_id", 'uint');
1381 if (! array_key_exists ($attr_id, $oldvalues))
1382 throw new InvalidRequestArgException ('attr_id', $attr_id, 'malformed request');
1383 $value = genericAssertion ("${i}_value", 'string0');
1384
1385 // If the object is a rack, skip certain attributes as they are handled elsewhere
1386 // (height, sort_order)
1387 if ($type_id == 1560 && ($attr_id == 27 || $attr_id == 29))
1388 continue;
1389
1390 // Delete attribute and move on, when the field is empty or if the field
1391 // type is a dictionary and it is the "--NOT SET--" value of 0.
1392 if ($value == '' || ($oldvalues[$attr_id]['type'] == 'dict' && $value == 0))
1393 {
1394 if (permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $attr_id))))
1395 commitUpdateAttrValue ($object_id, $attr_id);
1396 else
1397 showError ('Permission denied, "' . $oldvalues[$attr_id]['name'] . '" left unchanged');
1398 continue;
1399 }
1400
1401 // The value could be uint/float, but we don't know ATM. Let SQL
1402 // server check this and complain.
1403 if ('date' == $oldvalues[$attr_id]['type'])
1404 $value = timestampFromDatetimestr (genericAssertion ("${i}_value", 'datetime'));
1405
1406 switch ($oldvalues[$attr_id]['type'])
1407 {
1408 case 'uint':
1409 case 'float':
1410 case 'string':
1411 case 'date':
1412 $oldvalue = $oldvalues[$attr_id]['value'];
1413 break;
1414 case 'dict':
1415 $oldvalue = $oldvalues[$attr_id]['key'];
1416 break;
1417 default:
1418 }
1419 if ($value === $oldvalue) // ('' == 0), but ('' !== 0)
1420 continue;
1421 if (permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $attr_id))))
1422 commitUpdateAttrValue ($object_id, $attr_id, $value);
1423 else
1424 showError ('Permission denied, "' . $oldvalues[$attr_id]['name'] . '" left unchanged');
1425 }
1426 }
1427
1428 function addMultipleObjects()
1429 {
1430 $taglist = genericAssertion ('taglist', 'array0');
1431 $max = genericAssertion ('num_records', 'uint');
1432 for ($i = 0; $i < $max; $i++)
1433 {
1434 $tid = genericAssertion ("${i}_object_type_id", 'uint0');
1435 assertStringArg ("${i}_object_name", TRUE);
1436 assertStringArg ("${i}_object_label", TRUE);
1437 assertStringArg ("${i}_object_asset_no", TRUE);
1438 $name = $_REQUEST["${i}_object_name"];
1439
1440 if ($tid == 0)
1441 continue; // Just skip on intact SELECT.
1442 try
1443 {
1444 $object_id = commitAddObject
1445 (
1446 $name,
1447 $_REQUEST["${i}_object_label"],
1448 $tid,
1449 $_REQUEST["${i}_object_asset_no"],
1450 $taglist
1451 );
1452 showSuccess ('added object ' . mkCellA (spotEntity ('object', $object_id)));
1453 }
1454 catch (RTDatabaseError $e)
1455 {
1456 showError ("Error creating object '$name': " . $e->getMessage());
1457 }
1458 }
1459 }
1460
1461 function addLotOfObjects()
1462 {
1463 $taglist = genericAssertion ('taglist', 'array0');
1464 assertStringArg ('namelist', TRUE);
1465 $global_type_id = genericAssertion ('global_type_id', 'uint0');
1466 if ($global_type_id == 0 || $_REQUEST['namelist'] == '')
1467 {
1468 showError ('Incomplete form has been ignored. Cheers.');
1469 return;
1470 }
1471 foreach (textareaCooked ($_REQUEST['namelist']) as $name)
1472 try
1473 {
1474 $object_id = commitAddObject ($name, NULL, $global_type_id, '', $taglist);
1475 showSuccess ('added object ' . mkCellA (spotEntity ('object', $object_id)));
1476 }
1477 catch (RackTablesError $e)
1478 {
1479 showError ("Failed to add object '$name': " . $e->getMessage());
1480 }
1481 }
1482
1483 function linkObjects ()
1484 {
1485 commitLinkEntities
1486 (
1487 genericAssertion ('parent_entity_type', 'string'),
1488 genericAssertion ('parent_entity_id', 'uint'),
1489 genericAssertion ('child_entity_type', 'string'),
1490 genericAssertion ('child_entity_id', 'uint')
1491 );
1492 showSuccess ('Container set successfully');
1493 }
1494
1495 function deleteObject ()
1496 {
1497 setFuncMessages (__FUNCTION__, array ('OK' => 7));
1498 $oinfo = spotEntity ('object', genericAssertion ('object_id', 'uint'));
1499
1500 $racklist = getResidentRacksData ($oinfo['id'], FALSE);
1501 commitDeleteObject ($oinfo['id']);
1502 foreach ($racklist as $rack_id)
1503 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1504 showFuncMessage (__FUNCTION__, 'OK', array ($oinfo['dname']));
1505 }
1506
1507 function resetObject ()
1508 {
1509 setFuncMessages (__FUNCTION__, array ('OK' => 57));
1510 $racklist = getResidentRacksData (getBypassValue(), FALSE);
1511 commitResetObject (getBypassValue());
1512 foreach ($racklist as $rack_id)
1513 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1514 showFuncMessage (__FUNCTION__, 'OK');
1515 }
1516
1517 function updateUI ()
1518 {
1519 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1520 $num_vars = genericAssertion ('num_vars', 'uint');
1521 try
1522 {
1523 for ($i = 0; $i < $num_vars; $i++)
1524 {
1525 assertStringArg ("${i}_varvalue", TRUE);
1526 $varname = genericAssertion ("${i}_varname", 'string');
1527 $varvalue = $_REQUEST["${i}_varvalue"];
1528 // If form value = value in DB, don't bother updating DB.
1529 if (isConfigVarChanged ($varname, $varvalue))
1530 setConfigVar ($varname, $varvalue);
1531 }
1532 }
1533 catch (InvalidArgException $iae)
1534 {
1535 throw $iae->newIRAE();
1536 }
1537 showFuncMessage (__FUNCTION__, 'OK');
1538 }
1539
1540 function saveMyPreferences ()
1541 {
1542 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1543 $num_vars = genericAssertion ('num_vars', 'uint');
1544
1545 for ($i = 0; $i < $num_vars; $i++)
1546 {
1547 assertStringArg ("${i}_varvalue", TRUE);
1548 $varname = genericAssertion ("${i}_varname", 'string');
1549 $varvalue = $_REQUEST["${i}_varvalue"];
1550
1551 // If form value = value in DB, don't bother updating DB
1552 if (!isConfigVarChanged($varname, $varvalue))
1553 continue;
1554 try
1555 {
1556 setUserConfigVar ($varname, $varvalue);
1557 }
1558 catch (InvalidArgException $iae)
1559 {
1560 throw $iae->newIRAE();
1561 }
1562 }
1563 showFuncMessage (__FUNCTION__, 'OK');
1564 }
1565
1566 function resetMyPreference ()
1567 {
1568 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1569 try
1570 {
1571 resetUserConfigVar (genericAssertion ('varname', 'string'));
1572 }
1573 catch (InvalidArgException $iae)
1574 {
1575 throw $iae->newIRAE();
1576 }
1577 showFuncMessage (__FUNCTION__, 'OK');
1578 }
1579
1580 // FIXME: Move the default values to dictionary.php and feed from there into
1581 // this function and the installer to avoid duplication.
1582 function resetUIConfig()
1583 {
1584 setFuncMessages (__FUNCTION__, array ('OK' => 57));
1585 $defaults = array
1586 (
1587 'MASSCOUNT' => '8',
1588 'MAXSELSIZE' => '30',
1589 'ROW_SCALE' => '2',
1590 'IPV4_ADDRS_PER_PAGE' => '256',
1591 'DEFAULT_RACK_HEIGHT' => '42',
1592 'DEFAULT_SLB_VS_PORT' => '',
1593 'DEFAULT_SLB_RS_PORT' => '',
1594 'DETECT_URLS' => 'no',
1595 'RACK_PRESELECT_THRESHOLD' => '1',
1596 'DEFAULT_IPV4_RS_INSERVICE' => 'no',
1597 'AUTOPORTS_CONFIG' => '4 = 1*33*kvm + 2*24*eth%u;15 = 1*446*kvm',
1598 'SHOW_EXPLICIT_TAGS' => 'yes',
1599 'SHOW_IMPLICIT_TAGS' => 'yes',
1600 'SHOW_AUTOMATIC_TAGS' => 'no',
1601 'DEFAULT_OBJECT_TYPE' => '4',
1602 'IPV4_AUTO_RELEASE' => '1',
1603 'SHOW_LAST_TAB' => 'yes',
1604 'EXT_IPV4_VIEW' => 'yes',
1605 'TREE_THRESHOLD' => '25',
1606 'IPV4_JAYWALK' => 'no',
1607 'ADDNEW_AT_TOP' => 'yes',
1608 'IPV4_TREE_SHOW_USAGE' => 'no',
1609 'PREVIEW_TEXT_MAXCHARS' => '10240',
1610 'PREVIEW_TEXT_ROWS' => '25',
1611 'PREVIEW_TEXT_COLS' => '80',
1612 'PREVIEW_IMAGE_MAXPXS' => '320',
1613 'VENDOR_SIEVE' => '',
1614 'IPV4LB_LISTSRC' => 'false',
1615 'IPV4OBJ_LISTSRC' => 'not ({$typeid_3} or {$typeid_9} or {$typeid_10} or {$typeid_11})',
1616 'IPV4NAT_LISTSRC' => '{$typeid_4} or {$typeid_7} or {$typeid_8} or {$typeid_798}',
1617 'ASSETWARN_LISTSRC' => '{$typeid_4} or {$typeid_7} or {$typeid_8}',
1618 'NAMEWARN_LISTSRC' => '{$typeid_4} or {$typeid_7} or {$typeid_8}',
1619 'RACKS_PER_ROW' => '12',
1620 'FILTER_PREDICATE_SIEVE' => '',
1621 'FILTER_DEFAULT_ANDOR' => 'and',
1622 'FILTER_SUGGEST_ANDOR' => 'yes',
1623 'FILTER_SUGGEST_TAGS' => 'yes',
1624 'FILTER_SUGGEST_PREDICATES' => 'yes',
1625 'FILTER_SUGGEST_EXTRA' => 'no',
1626 'DEFAULT_SNMP_COMMUNITY' => 'public',
1627 'IPV4_ENABLE_KNIGHT' => 'yes',
1628 'TAGS_TOPLIST_SIZE' => '50',
1629 'TAGS_QUICKLIST_SIZE' => '20',
1630 'TAGS_QUICKLIST_THRESHOLD' => '50',
1631 'ENABLE_MULTIPORT_FORM' => 'no',
1632 'DEFAULT_PORT_IIF_ID' => '1',
1633 'DEFAULT_PORT_OIF_IDS' => '1=24; 3=1078; 4=1077; 5=1079; 6=1080; 8=1082; 9=1084; 10=1588; 11=1668; 12=1589; 13=1590; 14=1591',
1634 'IPV4_TREE_RTR_AS_CELL' => 'no',
1635 'PROXIMITY_RANGE' => '0',
1636 'IPV4_TREE_SHOW_VLAN' => 'yes',
1637 'VLANSWITCH_LISTSRC' => '',
1638 'VLANIPV4NET_LISTSRC' => '',
1639 'DEFAULT_VDOM_ID' => '',
1640 'DEFAULT_VST_ID' => '',
1641 'STATIC_FILTER' => 'yes',
1642 '8021Q_DEPLOY_MINAGE' => '300',
1643 '8021Q_DEPLOY_MAXAGE' => '3600',
1644 '8021Q_DEPLOY_RETRY' => '10800',
1645 '8021Q_WRI_AFTER_CONFT_LISTSRC' => 'false',
1646 '8021Q_INSTANT_DEPLOY' => 'no',
1647 'CDP_RUNNERS_LISTSRC' => '',
1648 'LLDP_RUNNERS_LISTSRC' => '',
1649 'SHRINK_TAG_TREE_ON_CLICK' => 'yes',
1650 'MAX_UNFILTERED_ENTITIES' => '0',
1651 'SYNCDOMAIN_MAX_PROCESSES' => '0',
1652 'PORT_EXCLUSION_LISTSRC' => '{$typeid_3} or {$typeid_10} or {$typeid_11} or {$typeid_1505} or {$typeid_1506}',
1653 'FILTER_RACKLIST_BY_TAGS' => 'yes',
1654 'MGMT_PROTOS' => 'ssh: {$typeid_4}; telnet: {$typeid_8}',
1655 'SYNC_8021Q_LISTSRC' => '',
1656 'QUICK_LINK_PAGES' => 'depot,ipv4space,rackspace',
1657 'CACTI_LISTSRC' => 'false',
1658 'CACTI_RRA_ID' => '1',
1659 'MUNIN_LISTSRC' => 'false',
1660 'VIRTUAL_OBJ_LISTSRC' => '1504,1505,1506,1507',
1661 'DATETIME_ZONE' => 'UTC',
1662 'DATETIME_FORMAT' => '%Y-%m-%d',
1663 'SEARCH_DOMAINS' => '',
1664 '8021Q_EXTSYNC_LISTSRC' => 'false',
1665 '8021Q_MULTILINK_LISTSRC' => 'false',
1666 'REVERSED_RACKS_LISTSRC' => 'false',
1667 'NEAREST_RACKS_CHECKBOX' => 'yes',
1668 'SHOW_OBJECTTYPE' => 'yes',
1669 'IPV4_TREE_SHOW_UNALLOCATED' => 'yes',
1670 );
1671 foreach ($defaults as $name => $value)
1672 setConfigVar ($name, $value);
1673 showFuncMessage (__FUNCTION__, 'OK');
1674 }
1675
1676 // Add single record.
1677 function addRealServer ()
1678 {
1679 setFuncMessages (__FUNCTION__, array ('OK' => 48));
1680 addRStoRSPool
1681 (
1682 getBypassValue(),
1683 genericAssertion ('rsip', 'inet'),
1684 genericAssertion ('rsport', 'string0'),
1685 isCheckSet ('inservice', 'yesno'),
1686 genericAssertion ('rsconfig', 'string0'),
1687 genericAssertion ('comment', 'string0')
1688 );
1689 showFuncMessage (__FUNCTION__, 'OK');
1690 }
1691
1692 // Parse textarea submitted and try adding a real server for each line.
1693 function addRealServers ()
1694 {
1695 setFuncMessages (__FUNCTION__, array ('OK' => 37, 'ERR1' => 131));
1696 $format = genericAssertion ('format', 'string');
1697 $ngood = 0;
1698 // Keep in mind, that the text will have HTML entities (namely '>') escaped.
1699 foreach (explode ("\n", dos2unix (genericAssertion ('rawtext', 'string'))) as $line)
1700 {
1701 if ($line == '')
1702 continue;
1703 $match = array ();
1704 switch ($format)
1705 {
1706 case 'ipvs_2': // address and port only
1707 if (!preg_match ('/^ -> ([0-9\.]+):([0-9]+) /', $line, $match))
1708 if (!preg_match ('/^ -> \[([0-9a-fA-F:]+)\]:([0-9]+) /', $line, $match))
1709 continue;
1710 addRStoRSPool (getBypassValue(), ip_parse ($match[1]), $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), '');
1711 break;
1712 case 'ipvs_3': // address, port and weight
1713 if (!preg_match ('/^ -> ([0-9\.]+):([0-9]+) +[a-zA-Z]+ +([0-9]+) /', $line, $match))
1714 if (!preg_match ('/^ -> \[([0-9a-fA-F:]+)\]:([0-9]+) +[a-zA-Z]+ +([0-9]+) /', $line, $match))
1715 continue;
1716 addRStoRSPool (getBypassValue(), ip_parse ($match[1]), $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), 'weight ' . $match[3]);
1717 break;
1718 case 'ssv_2': // IP address and port
1719 if (!preg_match ('/^([0-9\.a-fA-F:]+) ([0-9]+)$/', $line, $match))
1720 continue;
1721 addRStoRSPool (getBypassValue(), ip_parse ($match[1]), $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), '');
1722 break;
1723 case 'ssv_1': // IP address
1724 if (! $ip_bin = ip_checkparse ($line))
1725 continue;
1726 addRStoRSPool (getBypassValue(), $ip_bin, 0, getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), '');
1727 break;
1728 default:
1729 showFuncMessage (__FUNCTION__, 'ERR1');
1730 return;
1731 }
1732 $ngood++;
1733 }
1734 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
1735 }
1736
1737 function addVService ()
1738 {
1739 assertStringArg ('name', TRUE);
1740 $proto = genericAssertion ('proto', 'enum/ipproto');
1741 usePreparedInsertBlade
1742 (
1743 'IPv4VS',
1744 array
1745 (
1746 'vip' => genericAssertion ('vip', 'inet'),
1747 'vport' => $proto == 'MARK' ? NULL : genericAssertion ('vport', 'uint'),
1748 'proto' => $proto,
1749 'name' => nullIfEmptyStr ($_REQUEST['name']),
1750 'vsconfig' => nullIfEmptyStr (genericAssertion ('vsconfig', 'string0')),
1751 'rsconfig' => nullIfEmptyStr (genericAssertion ('rsconfig', 'string0')),
1752 )
1753 );
1754 $vs_id = lastInsertID();
1755 lastCreated ('ipv4vs', $vs_id);
1756 if (isset ($_REQUEST['taglist']))
1757 produceTagsForNewRecord ('ipv4vs', genericAssertion ('taglist', 'array0'), $vs_id);
1758 $vsinfo = spotEntity ('ipv4vs', $vs_id);
1759 showSuccess (mkCellA ($vsinfo) . ' created successfully');
1760 }
1761
1762 function addVSG ()
1763 {
1764 $name = assertStringArg ('name');
1765 usePreparedInsertBlade ('VS', array ('name' => $name));
1766 $vs_id = lastInsertID();
1767 lastCreated ('ipvs', $vs_id);
1768 if (isset ($_REQUEST['taglist']))
1769 produceTagsForNewRecord ('ipvs', $_REQUEST['taglist'], $vs_id);
1770 $vsinfo = spotEntity ('ipvs', $vs_id);
1771 showSuccess (mkCellA ($vsinfo) . ' created successfully');
1772 }
1773
1774 function deleteVService ()
1775 {
1776 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1777 $vsinfo = spotEntity ('ipv4vs', genericAssertion ('vs_id', 'uint'));
1778 if ($vsinfo['refcnt'] != 0)
1779 {
1780 showError ("Could not delete linked virtual service");
1781 return;
1782 }
1783 commitDeleteVS ($vsinfo['id']);
1784 showFuncMessage (__FUNCTION__, 'OK');
1785 return buildRedirectURL ('ipv4slb', 'default');
1786 }
1787
1788 function deleteVS()
1789 {
1790 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1791 if (count (getTriplets ($vsinfo)) != 0)
1792 {
1793 showError ("Could not delete linked virtual service group");
1794 return;
1795 }
1796 commitDeleteVSG ($vsinfo['id']);
1797 showSuccess (formatEntityName ($vsinfo) . ' deleted');
1798 return buildRedirectURL ('ipv4slb', 'vs');
1799 }
1800
1801 function updateSLBDefConfig ()
1802 {
1803 setFuncMessages (__FUNCTION__, array ('OK' => 43));
1804 commitUpdateSLBDefConf
1805 (
1806 array
1807 (
1808 'vs' => genericAssertion ('vsconfig', 'string0'),
1809 'rs' => genericAssertion ('rsconfig', 'string0'),
1810 )
1811 );
1812 showFuncMessage (__FUNCTION__, 'OK');
1813 }
1814
1815 function updateRealServer ()
1816 {
1817 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1818 commitUpdateRS (
1819 genericAssertion ('rs_id', 'uint'),
1820 genericAssertion ('rsip', 'inet'),
1821 genericAssertion ('rsport', 'string0'),
1822 isCheckSet ('inservice', 'yesno'),
1823 genericAssertion ('rsconfig', 'string0'),
1824 genericAssertion ('comment', 'string0')
1825 );
1826 showFuncMessage (__FUNCTION__, 'OK');
1827 }
1828
1829 function updateVService ()
1830 {
1831 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1832 $vs_id = getBypassValue();
1833 $taglist = genericAssertion ('taglist', 'array0');
1834 $proto = genericAssertion ('proto', 'enum/ipproto');
1835 genericAssertion ('vport', $proto == 'MARK' ? 'string0' : 'uint');
1836 assertStringArg ('name', TRUE);
1837 commitUpdateVS (
1838 $vs_id,
1839 genericAssertion ('vip', 'inet'),
1840 $_REQUEST['vport'],
1841 $proto,
1842 $_REQUEST['name'],
1843 genericAssertion ('vsconfig', 'string0'),
1844 genericAssertion ('rsconfig', 'string0')
1845 );
1846 rebuildTagChainForEntity ('ipvs', $vs_id, buildTagChainFromIds ($taglist), TRUE);
1847 showFuncMessage (__FUNCTION__, 'OK');
1848 }
1849
1850 function updateVS ()
1851 {
1852 $taglist = genericAssertion ('taglist', 'array0');
1853 $vs_id = assertUIntArg ('vs_id');
1854 $name = assertStringArg ('name');
1855 $vsconfig = nullIfEmptyStr (assertStringArg ('vsconfig', TRUE));
1856 $rsconfig = nullIfEmptyStr (assertStringArg ('rsconfig', TRUE));
1857
1858 usePreparedUpdateBlade ('VS', array ('name' => $name, 'vsconfig' => $vsconfig, 'rsconfig' => $rsconfig), array ('id' => $vs_id));
1859 rebuildTagChainForEntity ('ipvs', $vs_id, buildTagChainFromIds ($taglist), TRUE);
1860 showSuccess ("Service updated successfully");
1861 }
1862
1863 function addIPToVS()
1864 {
1865 $ip_bin = assertIPArg ('ip');
1866 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1867 amplifyCell ($vsinfo);
1868 $row = array ('vs_id' => $vsinfo['id'], 'vip' => $ip_bin, 'vsconfig' => NULL, 'rsconfig' => NULL);
1869 if ($vip = isVIPEnabled ($row, $vsinfo['vips']))
1870 {
1871 showError ("Service already contains IP " . formatVSIP ($vip));
1872 return;
1873 }
1874 usePreparedInsertBlade ('VSIPs', $row);
1875 showSuccess ("IP addded");
1876 }
1877
1878 function addPortToVS()
1879 {
1880 $proto = genericAssertion ('proto', 'enum/ipproto');
1881 $vport = assertUIntArg ('port', TRUE);
1882 if ($proto == 'MARK')
1883 {
1884 if ($vport > 0xFFFFFFFF)
1885 {
1886 showError ("fwmark value is too large");
1887 return;
1888 }
1889 }
1890 else
1891 if ($vport == 0 || $vport >= 0xFFFF)
1892 {
1893 showError ("Invalid $proto port value");
1894 return;
1895 }
1896
1897 $vsinfo = spotEntity ('ipvs', getBypassValue());
1898 amplifyCell ($vsinfo);
1899 $row = array ('vs_id' => $vsinfo['id'], 'proto' => $proto, 'vport' => $vport, 'vsconfig' => NULL, 'rsconfig' => NULL);
1900 if ($port = isPortEnabled ($row, $vsinfo['ports']))
1901 {
1902 showError ("Service already contains port " . $port['proto'] . ' ' . $port['vport']);
1903 return;
1904 }
1905 usePreparedInsertBlade ('VSPorts', $row);
1906 showSuccess ("port addded");
1907 }
1908
1909 function updateIPInVS()
1910 {
1911 $vs_id = assertUIntArg ('vs_id');
1912 $ip_bin = assertIPArg ('ip');
1913 $vsconfig = nullIfEmptyStr (assertStringArg ('vsconfig', TRUE));
1914 $rsconfig = nullIfEmptyStr (assertStringArg ('rsconfig', TRUE));
1915 if (usePreparedUpdateBlade ('VSIPs', array ('vsconfig' => $vsconfig, 'rsconfig' => $rsconfig), array ('vs_id' => $vs_id, 'vip' => $ip_bin)))
1916 showSuccess ("IP configuration updated");
1917 else
1918 showNotice ("Nothing changed");
1919 }
1920
1921 function updatePortInVS()
1922 {
1923 $vs_id = assertUIntArg ('vs_id');
1924 $proto = assertStringArg ('proto');
1925 $vport = assertUIntArg ('port', TRUE);
1926 $vsconfig = nullIfEmptyStr (assertStringArg ('vsconfig', TRUE));
1927 $rsconfig = nullIfEmptyStr (assertStringArg ('rsconfig', TRUE));
1928 if (usePreparedUpdateBlade ('VSPorts', array ('vsconfig' => $vsconfig, 'rsconfig' => $rsconfig), array ('vs_id' => $vs_id, 'proto' => $proto, 'vport' => $vport)))
1929 showSuccess ("Port configuration updated");
1930 else
1931 showNotice ("Nothing changed");
1932 }
1933
1934 function removeIPFromVS()
1935 {
1936 $vip = array ('vip' => assertIPArg ('ip'));
1937 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1938 amplifyCell ($vsinfo);
1939 $used = 0;
1940 foreach (getTriplets ($vsinfo) as $triplet)
1941 if (isVIPEnabled ($vip, $triplet['vips']))
1942 $used++;
1943 if (usePreparedDeleteBlade ('VSIPs', array ('vs_id' => $vsinfo['id']) + $vip))
1944 showSuccess ("IP removed" . ($used ? ", it was binded with $used SLBs" : ''));
1945 else
1946 showNotice ("Nothing changed");
1947 }
1948
1949 function removePortFromVS()
1950 {
1951 $port = array ('proto' => assertStringArg ('proto'), 'vport' => assertUIntArg ('port', TRUE));
1952 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1953 amplifyCell ($vsinfo);
1954 $used = 0;
1955 foreach (getTriplets ($vsinfo) as $triplet)
1956 if (isPortEnabled ($port, $triplet['ports']))
1957 $used++;
1958 if (usePreparedDeleteBlade ('VSPorts', array ('vs_id' => $vsinfo['id']) + $port))
1959 showSuccess ("Port removed" . ($used ? ", it was binded with $used SLBs" : ''));
1960 else
1961 showNotice ("Nothing changed");
1962 }
1963
1964 function updateTripletConfig()
1965 {
1966 global $op;
1967 $key_fields = array
1968 (
1969 'object_id' => assertUIntArg ('object_id'),
1970 'vs_id' => assertUIntArg ('vs_id'),
1971 'rspool_id' => assertUIntArg ('rspool_id'),
1972 );
1973 $config_fields = array
1974 (
1975 'vsconfig' => nullIfEmptyStr (assertStringArg ('vsconfig', TRUE)),
1976 'rsconfig' => nullIfEmptyStr (assertStringArg ('rsconfig', TRUE)),
1977 );
1978
1979 $vsinfo = spotEntity ('ipvs', $key_fields['vs_id']);
1980 amplifyCell ($vsinfo);
1981 $found = FALSE;
1982
1983 if ($op == 'updPort')
1984 {
1985 $table = 'VSEnabledPorts';
1986 $proto = assertStringArg ('proto');
1987 $vport = assertUIntArg ('port', TRUE);
1988 $key_fields['proto'] = $proto;
1989 $key_fields['vport'] = $vport;
1990 $key = "Port $proto-$vport";
1991 // check if such port exists in VS
1992 foreach ($vsinfo['ports'] as $vs_port)
1993 if ($vs_port['proto'] == $proto && $vs_port['vport'] == $vport)
1994 {
1995 $found = TRUE;
1996 break;
1997 }
1998 }
1999 else
2000 {
2001 $table = 'VSEnabledIPs';
2002 $vip = assertIPArg ('vip');
2003 $config_fields['prio'] = nullIfEmptyStr (assertStringArg ('prio', TRUE));
2004 $key_fields['vip'] = $vip;
2005 $key = "IP " . ip_format ($vip);
2006 // check if such VIP exists in VS
2007 foreach ($vsinfo['vips'] as $vs_vip)
2008 if ($vs_vip['vip'] === $vip)
2009 {
2010 $found = TRUE;
2011 break;
2012 }
2013 }
2014 if (! $found)
2015 {
2016 showError ("$key not found in VS");
2017 return;
2018 }
2019
2020 $nchanged = 0;
2021 if (! isCheckSet ('enabled'))
2022 {
2023 if ($nchanged += usePreparedDeleteBlade ($table, $key_fields))
2024 {
2025 showSuccess ("$key disabled");
2026 return;
2027 }
2028 }
2029 else
2030 {
2031 global $dbxlink;
2032 $dbxlink->beginTransaction();
2033 $q = "SELECT * FROM $table WHERE";
2034 $sep = '';
2035 $params = array();
2036 foreach ($key_fields as $field => $value)
2037 {
2038 $q .= " $sep $field = ?";
2039 $params[] = $value;
2040 $sep = 'AND';
2041 }
2042 $result = usePreparedSelectBlade ("$q FOR UPDATE", $params);
2043 $row = $result->fetch (PDO::FETCH_ASSOC);
2044 unset ($result);
2045 if ($row)
2046 {
2047 if ($nchanged += usePreparedUpdateBlade ($table, $config_fields, $key_fields))
2048 showSuccess ("$key config updated");
2049 }
2050 else
2051 {
2052 if (
2053 $nchanged += ($table == 'VSEnabledIPs' ?
2054 addSLBIPLink ($key_fields + $config_fields) :
2055 addSLBPortLink ($key_fields + $config_fields)
2056 )
2057 )
2058 showSuccess ("$key enabled");
2059 }
2060 $dbxlink->commit();
2061 }
2062 if (! $nchanged)
2063 showNotice ("No changes made");
2064 }
2065
2066 function removeTriplet()
2067 {
2068 $key_fields = array
2069 (
2070 'object_id' => assertUIntArg ('object_id'),
2071 'vs_id' => assertUIntArg ('vs_id'),
2072 'rspool_id' => assertUIntArg ('rspool_id'),
2073 );
2074
2075 global $dbxlink;
2076 $dbxlink->beginTransaction();
2077 usePreparedDeleteBlade ('VSEnabledIPs', $key_fields);
2078 usePreparedDeleteBlade ('VSEnabledPorts', $key_fields);
2079 $dbxlink->commit();
2080 showSuccess ('Triplet deleted');
2081 }
2082
2083 function createTriplet()
2084 {
2085 global $dbxlink;
2086 $object_id = assertUIntArg ('object_id');
2087 $vs_id = assertUIntArg ('vs_id');
2088 $rspool_id = assertUIntArg ('rspool_id');
2089 $vips = genericAssertion ('enabled_vips', 'array0');
2090 $ports = genericAssertion ('enabled_ports', 'array0');
2091
2092 $vsinfo = spotEntity ('ipvs', $vs_id);
2093 amplifyCell ($vsinfo);
2094 try
2095 {
2096 $dbxlink->beginTransaction();
2097 foreach ($vsinfo['vips'] as $vip)
2098 if (in_array (ip_format ($vip['vip']), $vips))
2099 addSLBIPLink (array ('object_id' => $object_id, 'vs_id' => $vs_id, 'rspool_id' => $rspool_id, 'vip' => $vip['vip']));
2100 foreach ($vsinfo['ports'] as $port)
2101 if (in_array($port['proto'] . '-' . $port['vport'], $ports))
2102 addSLBPortLink (array ('object_id' => $object_id, 'vs_id' => $vs_id, 'rspool_id' => $rspool_id, 'proto' => $port['proto'], 'vport' => $port['vport']));
2103 $dbxlink->commit();
2104 }
2105 catch (RTDatabaseError $e)
2106 {
2107 $dbxlink->rollBack();
2108 throw $e;
2109 }
2110 showSuccess ("SLB triplet created");
2111 }
2112
2113 function addLoadBalancer ()
2114 {
2115 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2116 assertStringArg ('prio', TRUE);
2117
2118 addLBtoRSPool (
2119 genericAssertion ('pool_id', 'uint'),
2120 genericAssertion ('object_id', 'uint'),
2121 genericAssertion ('vs_id', 'uint'),
2122 genericAssertion ('vsconfig', 'string0'),
2123 genericAssertion ('rsconfig', 'string0'),
2124 $_REQUEST['prio']
2125 );
2126 showFuncMessage (__FUNCTION__, 'OK');
2127 }
2128
2129 function addRSPool ()
2130 {
2131 assertStringArg ('name');
2132 $pool_id = commitCreateRSPool
2133 (
2134 $_REQUEST['name'],
2135 genericAssertion ('vsconfig', 'string0'),
2136 genericAssertion ('rsconfig', 'string0'),
2137 isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array()
2138 );
2139 showSuccess ('RS pool ' . mkA ($_REQUEST['name'], 'ipv4rspool', $pool_id) . ' created successfully');
2140 }
2141
2142 function deleteRSPool ()
2143 {
2144 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2145 $poolinfo = spotEntity ('ipv4rspool', genericAssertion ('pool_id', 'uint'));
2146 if ($poolinfo['refcnt'] != 0)
2147 {
2148 showError ("Could not delete linked RS pool");
2149 return;
2150 }
2151 commitDeleteRSPool ($poolinfo['id']);
2152 showFuncMessage (__FUNCTION__, 'OK');
2153 return buildRedirectURL ('ipv4slb', 'rspools');
2154 }
2155
2156 function importPTRData ()
2157 {
2158 setFuncMessages (__FUNCTION__, array ('OK' => 26, 'ERR' => 141));
2159 $net = spotEntity ('ipv4net', getBypassValue());
2160 $addrcount = genericAssertion ('addrcount', 'uint');
2161 $nbad = $ngood = 0;
2162 for ($i = 1; $i <= $addrcount; $i++)
2163 {
2164 $inputname = "import_${i}";
2165 if (! isCheckSet ($inputname))
2166 continue;
2167 $ip_bin = assertIPv4Arg ("addr_${i}");
2168 assertStringArg ("descr_${i}", TRUE);
2169 assertStringArg ("rsvd_${i}");
2170 // Non-existent addresses will not have this argument set in request.
2171 $rsvd = 'no';
2172 if ($_REQUEST["rsvd_${i}"] == 'yes')
2173 $rsvd = 'yes';
2174 try
2175 {
2176 if (! ip_in_range ($ip_bin, $net))
2177 throw new InvalidArgException ('ip_bin', $ip_bin);
2178 updateAddress ($ip_bin, $_REQUEST["descr_${i}"], $rsvd);
2179 $ngood++;
2180 }
2181 catch (RackTablesError $e)
2182 {
2183 $nbad++;
2184 }
2185 }
2186 if (!$nbad)
2187 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
2188 else
2189 showFuncMessage (__FUNCTION__, 'ERR', array ($nbad, $ngood));
2190 }
2191
2192 function generateAutoPorts ()
2193 {
2194 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2195 $object = spotEntity ('object', getBypassValue());
2196 executeAutoPorts ($object['id']);
2197 showFuncMessage (__FUNCTION__, 'OK');
2198 return buildRedirectURL (NULL, 'ports');
2199 }
2200
2201 function updateTag ()
2202 {
2203 try
2204 {
2205 commitUpdateTag
2206 (
2207 genericAssertion ('tag_id', 'uint'),
2208 genericAssertion ('tag_name', 'tag'),
2209 genericAssertion ('parent_id', 'uint0'),
2210 genericAssertion ('is_assignable', 'enum/yesno')
2211 );
2212 }
2213 catch (InvalidArgException $iae)
2214 {
2215 throw $iae->newIRAE();
2216 }
2217 showSuccess ('Tag updated successfully');
2218 }
2219
2220 function saveEntityTags ()
2221 {
2222 setFuncMessages (__FUNCTION__, array ('OK' => 43));
2223 $realm = etypeByPageno();
2224 $entity_id = getBypassValue();
2225 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2226 rebuildTagChainForEntity ($realm, $entity_id, buildTagChainFromIds ($taglist), TRUE);
2227 showFuncMessage (__FUNCTION__, 'OK');
2228 }
2229
2230 function rollTags ()
2231 {
2232 setFuncMessages (__FUNCTION__, array ('OK' => 67, 'ERR' => 149));
2233 if (genericAssertion ('sum', 'string0') != genericAssertion ('realsum', 'uint'))
2234 {
2235 showFuncMessage (__FUNCTION__, 'ERR');
2236 return;
2237 }
2238 // Even if the user requested an empty tag list, don't bail out, but process existing
2239 // tag chains with "zero" extra. This will make sure, that the stuff processed will
2240 // have its chains refined to "normal" form.
2241 $extratags = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2242 $n_ok = 0;
2243 // Minimizing the extra chain early, so that tag rebuilder doesn't have to
2244 // filter out the same tag again and again. It will have own noise to cancel.
2245 $extrachain = getExplicitTagsOnly (buildTagChainFromIds ($extratags));
2246 foreach (listCells ('rack', getBypassValue()) as $rack)
2247 {
2248 if (rebuildTagChainForEntity ('rack', $rack['id'], $extrachain))
2249 $n_ok++;
2250 amplifyCell ($rack);
2251 foreach ($rack['mountedObjects'] as $object_id)
2252 if (rebuildTagChainForEntity ('object', $object_id, $extrachain))
2253 $n_ok++;
2254 }
2255 showFuncMessage (__FUNCTION__, 'OK', array ($n_ok));
2256 }
2257
2258 function changeMyPassword ()
2259 {
2260 setFuncMessages (__FUNCTION__, array ('OK' => 51, 'ERR1' => 150, 'ERR2' => 151, 'ERR3' => 152));
2261 global $remote_username, $user_auth_src;
2262 if ($user_auth_src != 'database')
2263 {
2264 showFuncMessage (__FUNCTION__, 'ERR1');
2265 return;
2266 }
2267 assertStringArg ('oldpassword');
2268 assertStringArg ('newpassword1');
2269 assertStringArg ('newpassword2');
2270 $remote_userid = getUserIDByUsername ($remote_username);
2271 $userinfo = spotEntity ('user', $remote_userid);
2272 if ($userinfo['user_password_hash'] != sha1 ($_REQUEST['oldpassword']))
2273 {
2274 showFuncMessage (__FUNCTION__, 'ERR2');
2275 return;
2276 }
2277 if ($_REQUEST['newpassword1'] != $_REQUEST['newpassword2'])
2278 {
2279 showFuncMessage (__FUNCTION__, 'ERR3');
2280 return;
2281 }
2282 commitUpdateUserAccount ($remote_userid, $userinfo['user_name'], $userinfo['user_realname'], sha1 ($_REQUEST['newpassword1']));
2283 showFuncMessage (__FUNCTION__, 'OK');
2284 }
2285
2286 function saveRackCode ()
2287 {
2288 setFuncMessages (__FUNCTION__, array ('OK' => 43, 'ERR1' => 154));
2289 assertStringArg ('rackcode');
2290 // For the test to succeed, unescape LFs, strip CRs.
2291 $newcode = dos2unix ($_REQUEST['rackcode']);
2292 $parseTree = getRackCode ($newcode);
2293 if ($parseTree['result'] != 'ACK')
2294 {
2295 showFuncMessage (__FUNCTION__, 'ERR1', array ($parseTree['load']));
2296 return;
2297 }
2298 saveScript ('RackCode', $newcode);
2299 saveScript ('RackCodeCache', base64_encode (serialize ($parseTree)));
2300 showFuncMessage (__FUNCTION__, 'OK');
2301 }
2302
2303 function submitSLBConfig ()
2304 {
2305 showNotice ("You should redefine submitSLBConfig ophandler in your local extension to install SLB config");
2306 }
2307
2308 function addLocation ()
2309 {
2310 setFuncMessages (__FUNCTION__, array ('OK' => 5));
2311 assertStringArg ('name');
2312
2313 $location_id = commitAddObject ($_REQUEST['name'], NULL, 1562, NULL);
2314 if (0 != $parent_id = genericAssertion ('parent_id', 'uint0'))
2315 commitLinkEntities ('location', $parent_id, 'location', $location_id);
2316 showSuccess ('added location ' . mkA ($_REQUEST['name'], 'location', $location_id));
2317 }
2318
2319 // This function is used by two forms:
2320 // - renderEditLocationForm - all attributes may be modified
2321 // - renderRackspaceLocationEditor - only the name and parent may be modified
2322 function updateLocation ()
2323 {
2324 setFuncMessages (__FUNCTION__, array ('OK' => 6));
2325 global $pageno;
2326 $location_id = genericAssertion ('location_id', 'uint');
2327 $parent_id = genericAssertion ('parent_id', 'uint0');
2328 assertStringArg ('name');
2329
2330 if ($pageno == 'location')
2331 {
2332 $taglist = genericAssertion ('taglist', 'array0');
2333 $has_problems = isCheckSet ('has_problems', 'yesno');
2334 assertStringArg ('comment', TRUE);
2335 commitUpdateObject ($location_id, $_REQUEST['name'], NULL, $has_problems, NULL, $_REQUEST['comment']);
2336 updateObjectAttributes ($location_id);
2337 rebuildTagChainForEntity ('location', $location_id, buildTagChainFromIds ($taglist), TRUE);
2338 }
2339 else
2340 commitRenameObject ($location_id, $_REQUEST['name']);
2341
2342 $locationData = spotEntity ('location', $location_id);
2343
2344 // parent_id was submitted, but no link exists - create it
2345 if ($parent_id > 0 && !$locationData['parent_id'])
2346 commitLinkEntities ('location', $parent_id, 'location', $location_id);
2347
2348 // parent_id was submitted, but it doesn't match the existing link - update it
2349 if ($parent_id > 0 && $parent_id != $locationData['parent_id'])
2350 commitUpdateEntityLink
2351 (
2352 'location', $locationData['parent_id'], 'location', $location_id,
2353 'location', $parent_id, 'location', $location_id
2354 );
2355
2356 // no parent_id was submitted, but a link exists - delete it
2357 if ($parent_id == 0 && $locationData['parent_id'])
2358 commitUnlinkEntities ('location', $locationData['parent_id'], 'location', $location_id);
2359
2360 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
2361 }
2362
2363 function deleteLocation ()
2364 {
2365 setFuncMessages (__FUNCTION__, array ('OK' => 7, 'ERR1' => 206));
2366 $location_id = genericAssertion ('location_id', 'uint');
2367 $locationData = spotEntity ('location', $location_id);
2368 amplifyCell ($locationData);
2369 if (count ($locationData['locations']) || count ($locationData['rows']))
2370 {
2371 showFuncMessage (__FUNCTION__, 'ERR1', array ($locationData['name']));
2372 return;
2373 }
2374 releaseFiles ('location', $location_id);
2375 destroyTagsForEntity ('location', $location_id);
2376 commitDeleteObject ($location_id);
2377 showFuncMessage (__FUNCTION__, 'OK', array ($locationData['name']));
2378 return buildRedirectURL ('rackspace', 'editlocations');
2379 }
2380
2381 function addRow ()
2382 {
2383 setFuncMessages (__FUNCTION__, array ('OK' => 5));
2384 $location_id = genericAssertion ('location_id', 'uint0');
2385 assertStringArg ('name');
2386 $row_id = commitAddObject ($_REQUEST['name'], NULL, 1561, NULL);
2387 if ($location_id)
2388 commitLinkEntities ('location', $location_id, 'row', $row_id);
2389 showSuccess ('added row ' . mkA ($_REQUEST['name'], 'row', $row_id));
2390 }
2391
2392 // This function is used by two forms:
2393 // - renderEditRowForm - all attributes may be modified
2394 // - renderRackspaceRowEditor - only the name and location may be modified
2395 function updateRow ()
2396 {
2397 setFuncMessages (__FUNCTION__, array ('OK' => 6));
2398 $row_id = genericAssertion ('row_id', 'uint');
2399 $location_id = genericAssertion ('location_id', 'uint0');
2400 assertStringArg ('name');
2401
2402 commitUpdateObject ($row_id, $_REQUEST['name'], NULL, 'no', NULL, NULL);
2403
2404 global $pageno;
2405 if ($pageno == 'row')
2406 updateObjectAttributes ($row_id);
2407
2408 $rowData = spotEntity ('row', $row_id);
2409
2410 // location_id was submitted, but no link exists - create it
2411 if ($location_id > 0 && !$rowData['location_id'])
2412 commitLinkEntities ('location', $location_id, 'row', $row_id);
2413
2414 // location_id was submitted, but it doesn't match the existing link - update it
2415 if ($location_id > 0 && $location_id != $rowData['location_id'])
2416 commitUpdateEntityLink
2417 (
2418 'location', $rowData['location_id'], 'row', $row_id,
2419 'location', $location_id, 'row', $row_id
2420 );
2421
2422 // no parent_id was submitted, but a link exists - delete it
2423 if ($location_id == 0 && $rowData['location_id'])
2424 commitUnlinkEntities ('location', $rowData['location_id'], 'row', $row_id);
2425
2426 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
2427 }
2428
2429 function deleteRow ()
2430 {
2431 setFuncMessages (__FUNCTION__, array ('OK' => 7, 'UMOUNT' => 58));
2432 $row_id = assertUIntArg ('row_id');
2433 $rowData = spotEntity ('row', $row_id);
2434 $unmounted = getRowMountsCount ($row_id);
2435 commitDeleteRow ($row_id);
2436 if ($unmounted)
2437 showFuncMessage (__FUNCTION__, 'UMOUNT', array ($unmounted));
2438 showFuncMessage (__FUNCTION__, 'OK', array ($rowData['name']));
2439 return buildRedirectURL ('rackspace', 'editrows');
2440 }
2441
2442 function addRack ()
2443 {
2444 setFuncMessages (__FUNCTION__, array ('ERR2' => 172));
2445 $taglist = genericAssertion ('taglist', 'array0');
2446 $row_id = getBypassValue();
2447
2448 // The new rack(s) should be placed on the bottom of the list, sort-wise
2449 $rowInfo = getRowInfo ($row_id);
2450 $sort_order = $rowInfo['count']+1;
2451
2452 switch (genericAssertion ('mode', 'string'))
2453 {
2454 case 'one':
2455 assertStringArg ('name');
2456 $height = genericAssertion ('height1', 'uint');
2457 assertStringArg ('asset_no', TRUE);
2458 $rack_id = commitAddObject ($_REQUEST['name'], NULL, 1560, $_REQUEST['asset_no'], $taglist);
2459
2460 // Set the height and sort order
2461 commitUpdateAttrValue ($rack_id, 27, $height);
2462 commitUpdateAttrValue ($rack_id, 29, $sort_order);
2463
2464 // Link it to the row
2465 commitLinkEntities ('row', $row_id, 'rack', $rack_id);
2466 showSuccess ('added ' . mkCellA (spotEntity ('rack', $rack_id)));
2467 break;
2468 case 'many':
2469 $height = genericAssertion ('height2', 'uint');
2470 assertStringArg ('names', TRUE);
2471 foreach (textareaCooked ($_REQUEST['names']) as $cname)
2472 {
2473 $rack_id = commitAddObject ($cname, NULL, 1560, NULL, $taglist);
2474
2475 // Set the height and sort order
2476 commitUpdateAttrValue ($rack_id, 27, $height);
2477 commitUpdateAttrValue ($rack_id, 29, $sort_order);
2478 $sort_order++;
2479
2480 // Link it to the row
2481 commitLinkEntities ('row', $row_id, 'rack', $rack_id);
2482 showSuccess ('added ' . mkCellA (spotEntity ('rack', $rack_id)));
2483 }
2484 break;
2485 default:
2486 showFuncMessage (__FUNCTION__, 'ERR2');
2487 }
2488 }
2489
2490 function updateRack ()
2491 {
2492 setFuncMessages (__FUNCTION__, array ('OK' => 6));
2493 $row_id = genericAssertion ('row_id', 'uint');
2494 assertStringArg ('name');
2495 $height = genericAssertion ('height', 'uint');
2496 assertStringArg ('asset_no', TRUE);
2497 assertStringArg ('comment', TRUE);
2498 $taglist = genericAssertion ('taglist', 'array0');
2499 $rack_id = getBypassValue();
2500 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
2501 commitUpdateRack
2502 (
2503 $rack_id,
2504 $row_id,
2505 $_REQUEST['name'],
2506 $height,
2507 isCheckSet ('has_problems', 'yesno'),
2508 $_REQUEST['asset_no'],
2509 $_REQUEST['comment']
2510 );
2511 updateObjectAttributes ($rack_id);
2512 rebuildTagChainForEntity ('rack', $rack_id, buildTagChainFromIds ($taglist), TRUE);
2513 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
2514 }
2515
2516 function deleteRack ()
2517 {
2518 setFuncMessages (__FUNCTION__, array ('OK' => 7, 'ERR1' => 206));
2519 $rackData = spotEntity ('rack', getBypassValue());
2520 amplifyCell ($rackData);
2521 if (!$rackData['isDeletable'])
2522 {
2523 showFuncMessage (__FUNCTION__, 'ERR1');
2524 return;
2525 }
2526 commitDeleteRack ($rackData['id']);
2527 showFuncMessage (__FUNCTION__, 'OK', array (formatEntityName ($rackData)));
2528 return buildRedirectURL ('rackspace', 'default');
2529 }
2530
2531 function cleanRack ()
2532 {
2533 setFuncMessages (__FUNCTION__, array ('OK' => 58));
2534 $rack_id = getBypassValue();
2535 $unmounted = getRackMountsCount ($rack_id);
2536 commitCleanRack ($rack_id);
2537 showFuncMessage (__FUNCTION__, 'OK', array ($unmounted));
2538 }
2539
2540 function updateRackDesign ()
2541 {
2542 $rackData = spotEntity ('rack', getBypassValue());
2543 amplifyCell ($rackData);
2544 applyRackDesignMask($rackData);
2545 if (processGridForm ($rackData, 'A', 'F'))
2546 showSuccess ("Saved successfully");
2547 else
2548 showNotice ("Nothing saved");
2549 }
2550
2551 function updateRackProblems ()
2552 {
2553 $rackData = spotEntity ('rack', getBypassValue());
2554 amplifyCell ($rackData);
2555 applyRackProblemMask($rackData);
2556 if (processGridForm ($rackData, 'F', 'U'))
2557 showSuccess ("Saved successfully");
2558 else
2559 showNotice ("Nothing saved");
2560 }
2561
2562 function querySNMPData ()
2563 {
2564 $ver = genericAssertion ('ver', 'uint');
2565 $snmpsetup = array ();
2566 switch ($ver)
2567 {
2568 case 1:
2569 case 2:
2570 genericAssertion ('community', 'string');
2571 $snmpsetup['community'] = $_REQUEST['community'];
2572 break;
2573 case 3:
2574 assertStringArg ('sec_name');
2575 assertStringArg ('sec_level');
2576 assertStringArg ('auth_protocol');
2577 assertStringArg ('auth_passphrase', TRUE);
2578 assertStringArg ('priv_protocol');
2579 assertStringArg ('priv_passphrase', TRUE);
2580
2581 $snmpsetup['sec_name'] = $_REQUEST['sec_name'];
2582 $snmpsetup['sec_level'] = $_REQUEST['sec_level'];
2583 $snmpsetup['auth_protocol'] = $_REQUEST['auth_protocol'];
2584 $snmpsetup['auth_passphrase'] = $_REQUEST['auth_passphrase'];
2585 $snmpsetup['priv_protocol'] = $_REQUEST['priv_protocol'];
2586 $snmpsetup['priv_passphrase'] = $_REQUEST['priv_passphrase'];
2587 break;
2588 default:
2589 throw new InvalidRequestArgException ('ver', $ver);
2590 }
2591 $snmpsetup['version'] = $ver;
2592 doSNMPmining (getBypassValue(), $snmpsetup); // shows message by itself
2593 }
2594
2595 // File-related functions
2596 function addFileWithoutLink ()
2597 {
2598 setFuncMessages (__FUNCTION__, array ('OK' => 5, 'ERR1' => 207));
2599 assertStringArg ('comment', TRUE);
2600
2601 // Make sure the file can be uploaded
2602 if (get_cfg_var('file_uploads') != 1)
2603 throw new RackTablesError ('file uploads not allowed, change "file_uploads" parameter in php.ini', RackTablesError::MISCONFIGURED);
2604
2605 // Exit if the upload failed
2606 if ($_FILES['file']['error'])
2607 {
2608 showFuncMessage (__FUNCTION__, 'ERR1', array ($_FILES['file']['error']));
2609 return;
2610 }
2611 if (FALSE === $fp = fopen($_FILES['file']['tmp_name'], 'rb'))
2612 {
2613 showFuncMessage (__FUNCTION__, 'ERR1', array ('failed to access the temporary file'));
2614 return;
2615 }
2616
2617 $file_id = commitAddFile ($_FILES['file']['name'], $_FILES['file']['type'], $fp, genericAssertion ('comment', 'string0'));
2618 if (isset ($_REQUEST['taglist']))
2619 produceTagsForNewRecord ('file', $_REQUEST['taglist'], $file_id);
2620 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($_FILES['file']['name'])));
2621 }
2622
2623 function addFileToEntity ()
2624 {
2625 setFuncMessages (__FUNCTION__, array ('OK' => 5, 'ERR1' => 207));
2626 $realm = etypeByPageno();
2627 assertStringArg ('comment', TRUE);
2628
2629 // Make sure the file can be uploaded
2630 if (get_cfg_var('file_uploads') != 1)
2631 throw new RackTablesError ('file uploads not allowed, change "file_uploads" parameter in php.ini', RackTablesError::MISCONFIGURED);
2632
2633 // Exit if the upload failed
2634 if ($_FILES['file']['error'])
2635 {
2636 showFuncMessage (__FUNCTION__, 'ERR1', array ($_FILES['file']['error']));
2637 return;
2638 }
2639 if (FALSE === $fp = fopen($_FILES['file']['tmp_name'], 'rb'))
2640 {
2641 showFuncMessage (__FUNCTION__, 'ERR1', array ('failed to access the temporary file'));
2642 return;
2643 }
2644
2645 commitAddFile ($_FILES['file']['name'], $_FILES['file']['type'], $fp, genericAssertion ('comment', 'string0'));
2646 usePreparedInsertBlade
2647 (
2648 'FileLink',
2649 array
2650 (
2651 'file_id' => lastInsertID(),
2652 'entity_type' => $realm,
2653 'entity_id' => getBypassValue(),
2654 )
2655 );
2656 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($_FILES['file']['name'])));
2657 }
2658
2659 function linkFileToEntity ()
2660 {
2661 setFuncMessages (__FUNCTION__, array ('OK' => 71));
2662 $fi = spotEntity ('file', genericAssertion ('file_id', 'uint'));
2663 usePreparedInsertBlade
2664 (
2665 'FileLink',
2666 array
2667 (
2668 'file_id' => $fi['id'],
2669 'entity_type' => etypeByPageno(),
2670 'entity_id' => getBypassValue(),
2671 )
2672 );
2673 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($fi['name'])));
2674 }
2675
2676 function replaceFile ()
2677 {
2678 setFuncMessages (__FUNCTION__, array ('OK' => 6, 'ERR2' => 201));
2679 // Make sure the file can be uploaded
2680 if (get_cfg_var('file_uploads') != 1)
2681 throw new RackTablesError ('file uploads not allowed, change "file_uploads" parameter in php.ini', RackTablesError::MISCONFIGURED);
2682 $shortInfo = spotEntity ('file', getBypassValue());
2683
2684 if (FALSE === $fp = fopen ($_FILES['file']['tmp_name'], 'rb'))
2685 {
2686 showFuncMessage (__FUNCTION__, 'ERR2');
2687 return;
2688 }
2689 commitReplaceFile ($shortInfo['id'], $fp);
2690
2691 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($shortInfo['name'])));
2692 }
2693
2694 function unlinkFile ()
2695 {
2696 setFuncMessages (__FUNCTION__, array ('OK' => 72));
2697 commitUnlinkFile (genericAssertion ('link_id', 'uint'));
2698 showFuncMessage (__FUNCTION__, 'OK');
2699 }
2700
2701 function deleteFile ()
2702 {
2703 setFuncMessages (__FUNCTION__, array ('OK' => 7));
2704 $file_id = genericAssertion ('file_id', 'uint');
2705 $shortInfo = spotEntity ('file', $file_id);
2706 commitDeleteFile ($file_id);
2707 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($shortInfo['name'])));
2708 }
2709
2710 function updateFileText ()
2711 {
2712 setFuncMessages (__FUNCTION__, array ('OK' => 6, 'ERR1' => 179, 'ERR2' => 155));
2713 $shortInfo = spotEntity ('file', getBypassValue());
2714 if ($shortInfo['mtime'] != genericAssertion ('mtime_copy', 'string'))
2715 {
2716 showFuncMessage (__FUNCTION__, 'ERR1');
2717 return;
2718 }
2719 commitReplaceFile ($shortInfo['id'], genericAssertion ('file_text', 'string0'));
2720 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($shortInfo['name'])));
2721 }
2722
2723 function addIIFOIFCompatPack ()
2724 {
2725 setFuncMessages (__FUNCTION__, array ('OK' => 37));
2726 $standard = genericAssertion ('standard', 'enum/wdmstd');
2727 $iif_id = genericAssertion ('iif_id', 'iif');
2728 global $wdm_packs;
2729 $ngood = 0;
2730 foreach ($wdm_packs[$standard]['oif_ids'] as $oif_id)
2731 {
2732 commitSupplementPIC ($iif_id, $oif_id);
2733 $ngood++;
2734 }
2735 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
2736 }
2737
2738 function addOIFCompat ()
2739 {
2740 $type1 = assertUIntArg ('type1');
2741 $type2 = assertUIntArg ('type2');
2742 $n_changed = addPortOIFCompat ($type1, $type2);
2743 showSuccess ("$n_changed row(s) added");
2744 }
2745
2746 function delOIFCompat ()
2747 {
2748 $type1 = assertUIntArg ('type1');
2749 $type2 = assertUIntArg ('type2');
2750 $n_changed = deletePortOIFCompat ($type1, $type2);
2751 showSuccess ("$n_changed row(s) deleted");
2752 }
2753
2754 function delIIFOIFCompatPack ()
2755 {
2756 setFuncMessages (__FUNCTION__, array ('OK' => 38));
2757 $standard = genericAssertion ('standard', 'enum/wdmstd');
2758 $iif_id = genericAssertion ('iif_id', 'iif');
2759 global $wdm_packs;
2760 $ngood = 0;
2761 foreach ($wdm_packs[$standard]['oif_ids'] as $oif_id)
2762 {
2763 usePreparedDeleteBlade ('PortInterfaceCompat', array ('iif_id' => $iif_id, 'oif_id' => $oif_id));
2764 $ngood++;
2765 }
2766 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
2767 }
2768
2769 function addOIFCompatPack ()
2770 {
2771 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2772 global $wdm_packs;
2773 $oifs = $wdm_packs[genericAssertion ('standard', 'enum/wdmstd')]['oif_ids'];
2774 foreach ($oifs as $oif_id_1)
2775 {
2776 $args = $qmarks = array();
2777 $query = 'REPLACE INTO PortCompat (type1, type2) VALUES ';
2778 foreach ($oifs as $oif_id_2)
2779 {
2780 $qmarks[] = '(?, ?)';
2781 $args[] = $oif_id_1;
2782 $args[] = $oif_id_2;
2783 }
2784 $query .= implode (', ', $qmarks);
2785 usePreparedExecuteBlade ($query, $args);
2786 }
2787 showFuncMessage (__FUNCTION__, 'OK');
2788 }
2789
2790 function delOIFCompatPack ()
2791 {
2792 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2793 global $wdm_packs;
2794 $oifs = $wdm_packs[genericAssertion ('standard', 'enum/wdmstd')]['oif_ids'];
2795 foreach ($oifs as $oif_id_1)
2796 foreach ($oifs as $oif_id_2)
2797 if ($oif_id_1 != $oif_id_2) # leave narrow-band mapping intact
2798 usePreparedDeleteBlade ('PortCompat', array ('type1' => $oif_id_1, 'type2' => $oif_id_2));
2799 showFuncMessage (__FUNCTION__, 'OK');
2800 }
2801
2802 function add8021QOrder ()
2803 {
2804 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2805 $vdom_id = genericAssertion ('vdom_id', 'uint');
2806 $object_id = genericAssertion ('object_id', 'uint');
2807 $vst_id = genericAssertion ('vst_id', 'uint');
2808 global $pageno;
2809 fixContext();
2810 if ($pageno != 'object')
2811 spreadContext (spotEntity ('object', $object_id));
2812 if ($pageno != 'vst')
2813 spreadContext (spotEntity ('vst', $vst_id));
2814 assertPermission();
2815 usePreparedExecuteBlade
2816 (
2817 'INSERT INTO VLANSwitch (domain_id, object_id, template_id, last_change, out_of_sync) ' .
2818 'VALUES (?, ?, ?, NOW(), "yes")',
2819 array ($vdom_id, $object_id, $vst_id)
2820 );
2821 showFuncMessage (__FUNCTION__, 'OK');
2822 }
2823
2824 function del8021QOrder ()
2825 {
2826 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2827 $object_id = genericAssertion ('object_id', 'uint');
2828 $vdom_id = genericAssertion ('vdom_id', 'uint');
2829 $vst_id = genericAssertion ('vst_id', 'uint');
2830 global $pageno;
2831 fixContext();
2832 if ($pageno != 'object')
2833 spreadContext (spotEntity ('object', $object_id));
2834 if ($pageno != 'vst')
2835 spreadContext (spotEntity ('vst', $vst_id));
2836 assertPermission();
2837 usePreparedDeleteBlade ('VLANSwitch', array ('object_id' => $object_id));
2838 $focus_hints = array
2839 (
2840 'prev_objid' => $object_id,
2841 'prev_vstid' => $vst_id,
2842 'prev_vdid' => $vdom_id,
2843 );
2844 showFuncMessage (__FUNCTION__, 'OK');
2845 return buildRedirectURL (NULL, NULL, $focus_hints);
2846 }
2847
2848 function createVLANDomain ()
2849 {
2850 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2851 usePreparedInsertBlade
2852 (
2853 'VLANDomain',
2854 array
2855 (
2856 'description' => genericAssertion ('vdom_descr', 'string'),
2857 )
2858 );
2859 $domain_id = lastInsertID();
2860 lastCreated ('vdom', $domain_id);
2861 usePreparedInsertBlade
2862 (
2863 'VLANDescription',
2864 array
2865 (
2866 'domain_id' => $domain_id,
2867 'vlan_id' => VLAN_DFL_ID,
2868 'vlan_type' => 'compulsory',
2869 'vlan_descr' => 'default',
2870 )
2871 );
2872 showFuncMessage (__FUNCTION__, 'OK');
2873 }
2874
2875 function save8021QPorts ()
2876 {
2877 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2878 global $sic;
2879 $object_id = getBypassValue();
2880 $form_mode = genericAssertion ('form_mode', 'string');
2881 if ($form_mode != 'save' && $form_mode != 'duplicate')
2882 throw new InvalidRequestArgException ('form_mode', $form_mode);
2883 $extra = array();
2884
2885 // prepare the $changes array
2886 $changes = array();
2887 switch ($form_mode)
2888 {
2889 case 'save':
2890 $nports = genericAssertion ('nports', 'uint');
2891 if ($nports == 1)
2892 $extra = array ('port_name' => genericAssertion ('pn_0', 'string'));
2893 for ($i = 0; $i < $nports; $i++)
2894 {
2895 $portname = assertStringArg ('pn_' . $i);
2896 $portmode = assertStringArg ('pm_' . $i);
2897 // An access port only generates form input for its native VLAN,
2898 // which we derive allowed VLAN list from.
2899 $native = isset ($sic['pnv_' . $i]) ? $sic['pnv_' . $i] : 0;
2900 switch ($portmode)
2901 {
2902 case 'trunk':
2903 # assertArrayArg ('pav_' . $i);
2904 $allowed = isset ($sic['pav_' . $i]) ? $sic['pav_' . $i] : array();
2905 break;
2906 case 'access':
2907 if ($native == 'same')
2908 continue 2;
2909 assertUIntArg ('pnv_' . $i);
2910 $allowed = array ($native);
2911 break;
2912 default:
2913 throw new InvalidRequestArgException ("pm_${i}", $portmode, 'unknown port mode');
2914 }
2915 $changes[$portname] = array
2916 (
2917 'mode' => $portmode,
2918 'allowed' => $allowed,
2919 'native' => $native,
2920 );
2921 }
2922 break;
2923 case 'duplicate':
2924 $from_port = genericAssertion ('from_port', 'string');
2925 $before = getStored8021QConfig ($object_id, 'desired');
2926 if (!array_key_exists ($from_port, $before))
2927 throw new InvalidArgException ('from_port', $from_port, 'this port does not exist');
2928 foreach (genericAssertion ('to_ports', 'array0') as $tpn)
2929 if (!array_key_exists ($tpn, $before))
2930 throw new InvalidArgException ('to_ports[]', $tpn, 'this port does not exist');
2931 elseif ($tpn != $from_port)
2932 $changes[$tpn] = $before[$from_port];
2933 break;
2934 }
2935 apply8021qChangeRequest ($object_id, $changes, TRUE, genericAssertion ('mutex_rev', 'uint0'));
2936 return buildRedirectURL (NULL, NULL, $extra);
2937 }
2938
2939 function bindVLANtoIPv4 ()
2940 {
2941 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2942 commitSupplementVLANIPv4 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2943 showFuncMessage (__FUNCTION__, 'OK');
2944 }
2945
2946 function bindVLANtoIPv6 ()
2947 {
2948 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2949 commitSupplementVLANIPv6 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2950 showFuncMessage (__FUNCTION__, 'OK');
2951 }
2952
2953 function unbindVLANfromIPv4 ()
2954 {
2955 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2956 commitReduceVLANIPv4 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2957 showFuncMessage (__FUNCTION__, 'OK');
2958 }
2959
2960 function unbindVLANfromIPv6 ()
2961 {
2962 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2963 commitReduceVLANIPv6 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2964 showFuncMessage (__FUNCTION__, 'OK');
2965 }
2966
2967 function process8021QSyncRequest ()
2968 {
2969 setFuncMessages (__FUNCTION__, array ('OK' => 63, 'ERR' => 191));
2970 // behave depending on current operation: exec8021QPull or exec8021QPush
2971 global $op;
2972 if (FALSE === $done = exec8021QDeploy (getBypassValue(), $op == 'exec8021QPush'))
2973 showFuncMessage (__FUNCTION__, 'ERR');
2974 else
2975 showFuncMessage (__FUNCTION__, 'OK', array ($done));
2976 }
2977
2978 function process8021QRecalcRequest ()
2979 {
2980 setFuncMessages (__FUNCTION__, array ('OK' => 87));
2981 assertPermission (NULL, NULL, NULL, array (array ('tag' => '$op_recalc8021Q')));
2982 $counters = recalc8021QPorts (getBypassValue());
2983 if ($counters['ports'])
2984 showFuncMessage (__FUNCTION__, 'OK', array ($counters['ports'], $counters['switches']));
2985 else
2986 showNotice ('No changes were made');
2987 }
2988
2989 function resolve8021QConflicts ()
2990 {
2991 setFuncMessages (__FUNCTION__, array ('OK' => 63, 'ERR1' => 179, 'ERR2' => 109));
2992 global $sic, $dbxlink;
2993 $mutex_rev = genericAssertion ('mutex_rev', 'uint0'); // counts from 0
2994 $nrows = genericAssertion ('nrows', 'uint');
2995 $object_id = getBypassValue();
2996 // Divide submitted radio buttons into 3 groups:
2997 // left (saved version wins)
2998 // asis (ignore)
2999 // right (running version wins)
3000 $F = array();
3001 for ($i = 0; $i < $nrows; $i++)
3002 {
3003 if (!array_key_exists ("i_${i}", $sic))
3004 continue;
3005 // let's hope other inputs are in place
3006 switch ($sic["i_${i}"])
3007 {
3008 case 'left':
3009 case 'right':
3010 $F[$sic["pn_${i}"]] = array
3011 (
3012 'mode' => $sic["rm_${i}"],
3013 'allowed' => array_fetch ($sic, "ra_${i}", array()),
3014 'native' => $sic["rn_${i}"],
3015 'decision' => $sic["i_${i}"],
3016 );
3017 break;
3018 default:
3019 // don't care
3020 }
3021 }
3022 $dbxlink->beginTransaction();
3023 try
3024 {
3025 if (NULL === $vswitch = getVLANSwitchInfo ($object_id, 'FOR UPDATE'))
3026 throw new InvalidArgException ('object_id', $object_id, 'VLAN domain is not set for this object');
3027 if ($vswitch['mutex_rev'] != $mutex_rev)
3028 throw new InvalidRequestArgException ('mutex_rev', $mutex_rev, 'expired form (table data has changed)');
3029 $D = getStored8021QConfig ($vswitch['object_id'], 'desired');
3030 $C = getStored8021QConfig ($vswitch['object_id'], 'cached');
3031 $R = getRunning8021QConfig ($vswitch['object_id']);
3032 $plan = get8021QSyncOptions ($vswitch, $D, $C, $R['portdata']);
3033 $ndone = 0;
3034 foreach ($F as $port_name => $port)
3035 {
3036 if (!array_key_exists ($port_name, $plan))
3037 continue;
3038 elseif ($plan[$port_name]['status'] == 'merge_conflict')
3039 {
3040 // for R neither mutex nor revisions can be emulated, but revision change can be
3041 if (!same8021QConfigs ($port, $R['portdata'][$port_name]))
3042 throw new InvalidRequestArgException ("port ${port_name}", '(hidden)', 'expired form (switch data has changed)');
3043 if ($port['decision'] == 'right') // D wins, frame R by writing value of R to C
3044 $ndone += upd8021QPort ('cached', $vswitch['object_id'], $port_name, $port, $C[$port_name]);
3045 elseif ($port['decision'] == 'left') // R wins, cross D up
3046 $ndone += upd8021QPort ('cached', $vswitch['object_id'], $port_name, $D[$port_name], $C[$port_name]);
3047 // otherwise there was no decision made
3048 }
3049 elseif
3050 (
3051 $plan[$port_name]['status'] == 'delete_conflict' or
3052 $plan[$port_name]['status'] == 'martian_conflict'
3053 )
3054 if ($port['decision'] == 'left')
3055 // confirm deletion of local copy
3056 $ndone += del8021QPort ($vswitch['object_id'], $port_name);
3057 // otherwise ignore a decision that doesn't address a conflict
3058 }
3059 }
3060 catch (InvalidRequestArgException $e)
3061 {
3062 $dbxlink->rollBack();
3063 showFuncMessage (__FUNCTION__, 'ERR1');
3064 return;
3065 }
3066 catch (Exception $e)
3067 {
3068 $dbxlink->rollBack();
3069 showFuncMessage (__FUNCTION__, 'ERR2');
3070 return;
3071 }
3072 $dbxlink->commit();
3073 showFuncMessage (__FUNCTION__, 'OK', array ($ndone));
3074 }
3075
3076 function update8021QPortList()
3077 {
3078 genericAssertion ('ports', 'array');
3079 $enabled = $disabled = 0;
3080 $default_port = array
3081 (
3082 'mode' => 'access',
3083 'allowed' => array (VLAN_DFL_ID),
3084 'native' => VLAN_DFL_ID,
3085 );
3086 foreach (genericAssertion ('ports', 'array') as $line)
3087 if (preg_match ('/^enable (.+)$/', $line, $m))
3088 $enabled += add8021QPort (getBypassValue(), $m[1], $default_port);
3089 elseif (preg_match ('/^disable (.+)$/', $line, $m))
3090 $disabled += del8021QPort (getBypassValue(), $m[1]);
3091 else
3092 throw new InvalidRequestArgException ('ports[]', $line, 'malformed array item');
3093 # $enabled + $disabled > 0
3094 if ($enabled)
3095 showSuccess ("enabled 802.1Q for ${enabled} port(s)");
3096 if ($disabled)
3097 showSuccess ("disabled 802.1Q for ${disabled} port(s)");
3098 }
3099
3100 function cloneVST()
3101 {
3102 setFuncMessages (__FUNCTION__, array ('OK' => 48));
3103 $src_vst = spotEntity ('vst', genericAssertion ('from_id', 'uint'));
3104 amplifyCell ($src_vst);
3105 commitUpdateVSTRules (getBypassValue(), genericAssertion ('mutex_rev', 'uint0'), $src_vst['rules']);
3106 showFuncMessage (__FUNCTION__, 'OK');
3107 }
3108
3109 function updVSTRule()
3110 {
3111 setFuncMessages (__FUNCTION__, array ('OK' => 43));
3112 // this is used for making throwing an invalid argument exception easier.
3113 function updVSTRule_get_named_param ($name, $haystack, &$last_used_name)
3114 {
3115 $last_used_name = $name;
3116 return isset ($haystack[$name]) ? $haystack[$name] : NULL;
3117 }
3118
3119 global $port_role_options;
3120 $vst_id = getBypassValue();
3121 $taglist = genericAssertion ('taglist', 'array0');
3122 $mutex_rev = genericAssertion ('mutex_rev', 'uint0');
3123 $data = genericAssertion ('template_json', 'json');
3124 $rule_no = 0;
3125 try
3126 {
3127 $last_field = '';
3128 foreach ($data as $rule)
3129 {
3130 $rule_no++;
3131 if
3132 (
3133 ! isInteger (updVSTRule_get_named_param ('rule_no', $rule, $last_field)) ||
3134 ! isPCRE (updVSTRule_get_named_param ('port_pcre', $rule, $last_field)) ||
3135 NULL === updVSTRule_get_named_param ('port_role', $rule, $last_field) ||
3136 ! array_key_exists (updVSTRule_get_named_param ('port_role', $rule, $last_field), $port_role_options) ||
3137 NULL === updVSTRule_get_named_param ('wrt_vlans', $rule, $last_field) ||
3138 ! preg_match ('/^[ 0-9\-,]*$/', updVSTRule_get_named_param ('wrt_vlans', $rule, $last_field)) ||
3139 NULL === updVSTRule_get_named_param ('description', $rule</