refine exception class in addMultiPorts()
[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 commitAddPort
819 (
820 getBypassValue(),
821 trim ($_REQUEST['port_name']),
822 genericAssertion ('port_type_id', 'string'),
823 trim ($_REQUEST['port_label']),
824 trim (genericAssertion ('port_l2address', 'l2address0'))
825 );
826 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['port_name']));
827 }
828
829 function editPortForObject ()
830 {
831 setFuncMessages (__FUNCTION__, array ('OK' => 6));
832 global $sic;
833 $port_id = assertUIntArg ('port_id');
834 commitUpdatePort
835 (
836 getBypassValue(),
837 $port_id,
838 genericAssertion ('name', 'string'),
839 assertStringArg ('port_type_id'),
840 genericAssertion ('label', 'string0'),
841 genericAssertion ('l2address', 'l2address0'),
842 assertStringArg ('reservation_comment', TRUE)
843 );
844 if (array_key_exists ('cable', $_REQUEST))
845 commitUpdatePortLink ($port_id, $sic['cable']);
846 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
847 }
848
849 function addMultiPorts ()
850 {
851 setFuncMessages (__FUNCTION__, array ('OK' => 10));
852 assertStringArg ('input');
853 $format = genericAssertion ('format', 'string');
854 $port_type = genericAssertion ('port_type', 'string');
855 $object_id = getBypassValue();
856 $ports = array();
857 foreach (textareaCooked ($_REQUEST['input']) as $line)
858 {
859 switch ($format)
860 {
861 case 'ssv1':
862 $words = explode (' ', $line);
863 if ($words[0] == '') // empty L2 address is OK
864 continue;
865 $ports[] = array
866 (
867 'name' => $words[0],
868 'l2address' => array_fetch ($words, 1, ''),
869 'label' => ''
870 );
871 break;
872 default:
873 throw new RackTablesError ("unknown data format '${format}'", RackTablesError::INTERNAL);
874 }
875 }
876 // Create ports, if they don't exist.
877 $added_count = $updated_count = $error_count = 0;
878 foreach ($ports as $port)
879 {
880 $port_ids = getPortIDs ($object_id, $port['name']);
881 try
882 {
883 if (!count ($port_ids))
884 {
885 commitAddPort ($object_id, $port['name'], $port_type, $port['label'], $port['l2address']);
886 $added_count++;
887 }
888 elseif (count ($port_ids) == 1) // update only single-socket ports
889 {
890 $rsvc = getPortReservationComment (array_first ($port_ids));
891 commitUpdatePort ($object_id, $port_ids[0], $port['name'], $port_type, $port['label'], $port['l2address'], $rsvc);
892 $updated_count++;
893 }
894 }
895 catch (InvalidArgException $iae)
896 {
897 showError ($iae->getMessage());
898 }
899 }
900 showFuncMessage (__FUNCTION__, 'OK', array ($added_count, $updated_count, $error_count));
901 }
902
903 function addBulkPorts ()
904 {
905 setFuncMessages (__FUNCTION__, array ('OK' => 82));
906 assertStringArg ('port_name', TRUE);
907 assertStringArg ('port_label', TRUE);
908
909 $object_id = getBypassValue();
910 $port_name = $_REQUEST['port_name'];
911 $port_type_id = genericAssertion ('port_type_id', 'string');
912 $port_label = $_REQUEST['port_label'];
913 $port_numbering_start = genericAssertion ('port_numbering_start', 'uint0');
914 $port_numbering_count = genericAssertion ('port_numbering_count', 'uint');
915
916 $added_count = $error_count = 0;
917 if (strrpos ($port_name, '%u') === FALSE)
918 $port_name .= '%u';
919 if (strrpos ($port_label, '%u') === FALSE)
920 $port_label .= '%u';
921 for ($i = 0, $c = $port_numbering_start; $i < $port_numbering_count; $i++, $c++)
922 {
923 commitAddPort ($object_id, @sprintf ($port_name, $c), $port_type_id, @sprintf ($port_label, $c), '');
924 $added_count++;
925 }
926 showFuncMessage (__FUNCTION__, 'OK', array ($added_count, $error_count));
927 }
928
929 function updIPAllocation ()
930 {
931 setFuncMessages (__FUNCTION__, array ('OK' => 51));
932 $ip_bin = assertIPArg ('ip');
933 assertStringArg ('bond_name', TRUE);
934 updateIPBond
935 (
936 $ip_bin,
937 genericAssertion ('object_id', 'uint'),
938 $_REQUEST['bond_name'],
939 genericAssertion ('bond_type', 'enum/alloc_type')
940 );
941 showFuncMessage (__FUNCTION__, 'OK');
942 return buildRedirectURL (NULL, NULL, array ('hl_ip' => ip_format ($ip_bin)));
943 }
944
945 function delIPAllocation ()
946 {
947 setFuncMessages (__FUNCTION__, array ('OK' => 49));
948 unbindIPFromObject (genericAssertion ('ip', 'inet'), genericAssertion ('object_id', 'uint'));
949 showFuncMessage (__FUNCTION__, 'OK');
950 }
951
952 function addIPAllocation ()
953 {
954 setFuncMessages (__FUNCTION__, array ('OK' => 48, 'ERR1' => 170));
955 $ip_bin = assertIPArg ('ip');
956 $alloc_type = genericAssertion ('bond_type', 'enum/alloc_type');
957
958 // check if address is alread allocated
959 $address = getIPAddress($ip_bin);
960
961 if(!empty($address['allocs']) && ( ($address['allocs'][0]['type'] != 'shared') || ($alloc_type != 'shared') ) )
962 showWarning("IP ".ip_format($ip_bin)." already in use by ".$address['allocs'][0]['object_name']." - ".$address['allocs'][0]['name']);
963
964 if (getConfigVar ('IPV4_JAYWALK') != 'yes' && NULL === getIPAddressNetworkId ($ip_bin))
965 {
966 showFuncMessage (__FUNCTION__, 'ERR1', array (ip_format ($ip_bin)));
967 return;
968 }
969
970 if($address['reserved'] && $address['name'] != '')
971 {
972 showWarning("IP ".ip_format($ip_bin)." reservation \"".$address['name']."\" is removed");
973 //TODO ask to take reserved IP or not !
974 }
975
976 bindIPToObject
977 (
978 $ip_bin,
979 genericAssertion ('object_id', 'uint'),
980 genericAssertion ('bond_name', 'string0'),
981 $alloc_type
982 );
983
984 showFuncMessage (__FUNCTION__, 'OK');
985 return buildRedirectURL (NULL, NULL, array ('hl_ip' => ip_format ($ip_bin)));
986 }
987
988 function addIPv4Prefix ()
989 {
990 global $sic;
991 $vlan_ck = empty ($sic['vlan_ck']) ? NULL : genericAssertion ('vlan_ck', 'uint-vlan1');
992 $net_id = createIPv4Prefix
993 (
994 genericAssertion ('range', 'string'),
995 genericAssertion ('name', 'string0'),
996 isCheckSet ('is_connected'),
997 genericAssertion ('taglist', 'array0')
998 );
999 $net_cell = spotEntity ('ipv4net', $net_id);
1000 if (isset ($vlan_ck))
1001 {
1002 if (considerConfiguredConstraint ($net_cell, 'VLANIPV4NET_LISTSRC'))
1003 commitSupplementVLANIPv4 ($vlan_ck, $net_id);
1004 else
1005 showError ("VLAN binding to network " . mkCellA ($net_cell) . " is restricted in config");
1006 }
1007 showSuccess ('IP network ' . mkCellA ($net_cell) . ' has been created');
1008 }
1009
1010 function addIPv6Prefix ()
1011 {
1012 global $sic;
1013 $vlan_ck = empty ($sic['vlan_ck']) ? NULL : genericAssertion ('vlan_ck', 'uint-vlan1');
1014 $net_id = createIPv6Prefix
1015 (
1016 genericAssertion ('range', 'string'),
1017 genericAssertion ('name', 'string0'),
1018 isCheckSet ('is_connected'),
1019 genericAssertion ('taglist', 'array0')
1020 );
1021 $net_cell = spotEntity ('ipv6net', $net_id);
1022 if (isset ($vlan_ck))
1023 {
1024 if (considerConfiguredConstraint ($net_cell, 'VLANIPV4NET_LISTSRC'))
1025 commitSupplementVLANIPv6 ($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 delIPv4Prefix ()
1033 {
1034 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1035 $netinfo = spotEntity ('ipv4net', genericAssertion ('id', 'uint'));
1036 loadIPAddrList ($netinfo);
1037 if (! isIPNetworkEmpty ($netinfo))
1038 {
1039 showError ("There are allocations within prefix, delete forbidden");
1040 return;
1041 }
1042 if (array_key_exists ($netinfo['ip_bin'], $netinfo['addrlist']))
1043 updateV4Address ($netinfo['ip_bin'], '', 'no');
1044 $last_ip = ip_last ($netinfo);
1045 if (array_key_exists ($last_ip, $netinfo['addrlist']))
1046 updateV4Address ($last_ip, '', 'no');
1047 destroyIPv4Prefix ($netinfo['id']);
1048 showFuncMessage (__FUNCTION__, 'OK');
1049 global $pageno;
1050 if ($pageno == 'ipv4net')
1051 return buildRedirectURL ('index', 'default');
1052 }
1053
1054 function delIPv6Prefix ()
1055 {
1056 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1057 $netinfo = spotEntity ('ipv6net', 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 updateV6Address ($netinfo['ip_bin'], '', 'no');
1066 destroyIPv6Prefix ($netinfo['id']);
1067 showFuncMessage (__FUNCTION__, 'OK');
1068 global $pageno;
1069 if ($pageno == 'ipv6net')
1070 return buildRedirectURL ('index', 'default');
1071 }
1072
1073 function editAddress ()
1074 {
1075 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1076 assertStringArg ('name', TRUE);
1077 assertStringArg ('comment', TRUE);
1078 updateAddress
1079 (
1080 genericAssertion ('ip', 'inet'),
1081 $_REQUEST['name'],
1082 isCheckSet ('reserved', 'yesno'),
1083 $_REQUEST['comment']
1084 );
1085 showFuncMessage (__FUNCTION__, 'OK');
1086 }
1087
1088 function createUser ()
1089 {
1090 setFuncMessages (__FUNCTION__, array ('OK' => 5));
1091 assertStringArg ('username');
1092 assertStringArg ('realname', TRUE);
1093 assertStringArg ('password');
1094 $username = $_REQUEST['username'];
1095 $password = sha1 ($_REQUEST['password']);
1096 $user_id = commitCreateUserAccount ($username, $_REQUEST['realname'], $password);
1097 if (isset ($_REQUEST['taglist']))
1098 produceTagsForNewRecord ('user', $_REQUEST['taglist'], $user_id);
1099 showFuncMessage (__FUNCTION__, 'OK', array ($username));
1100 }
1101
1102 function updateUser ()
1103 {
1104 setFuncMessages (__FUNCTION__, array ('OK' => 6));
1105 $user_id = genericAssertion ('user_id', 'uint');
1106 $username = assertStringArg ('username');
1107 assertStringArg ('realname', TRUE);
1108 $new_password = assertStringArg ('password', TRUE);
1109 $userinfo = spotEntity ('user', $user_id);
1110 // Set new password only if provided.
1111 $new_password = $new_password != '' ? sha1 ($new_password) : $userinfo['user_password_hash'];
1112 commitUpdateUserAccount ($user_id, $username, $_REQUEST['realname'], $new_password);
1113 // if user account renaming is being performed, change key value in UserConfig table
1114 if ($userinfo['user_name'] !== $username)
1115 usePreparedUpdateBlade ('UserConfig', array ('user' => $username), array('user' => $userinfo['user_name']));
1116 showFuncMessage (__FUNCTION__, 'OK', array ($username));
1117 }
1118
1119 function supplementAttrMap ()
1120 {
1121 setFuncMessages (__FUNCTION__, array ('OK' => 48, 'ERR1' => 154));
1122 $attr_id = assertUIntArg ('attr_id');
1123 if (getAttrType ($attr_id) != 'dict')
1124 $chapter_id = NULL;
1125 else
1126 {
1127 try
1128 {
1129 $chapter_id = genericAssertion ('chapter_no', 'uint');
1130 }
1131 catch (InvalidRequestArgException $e)
1132 {
1133 showFuncMessage (__FUNCTION__, 'ERR1', array ('chapter not selected'));
1134 return;
1135 }
1136 }
1137 commitSupplementAttrMap ($attr_id, genericAssertion ('objtype_id', 'uint'), $chapter_id);
1138 showFuncMessage (__FUNCTION__, 'OK');
1139 }
1140
1141 function clearSticker ()
1142 {
1143 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1144 $attr_id = assertUIntArg ('attr_id');
1145 if (permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $attr_id))))
1146 commitUpdateAttrValue (getBypassValue(), $attr_id);
1147 else
1148 {
1149 $oldvalues = getAttrValues (getBypassValue());
1150 showError ('Permission denied, "' . $oldvalues[$attr_id]['name'] . '" left unchanged');
1151 }
1152 }
1153
1154 // This function accepts rack data returned by amplifyCell(), validates and applies changes
1155 // supplied in $_REQUEST and returns resulting array. Only those changes are examined that
1156 // correspond to current rack ID.
1157 // 1st arg is rackdata, 2nd arg is unchecked state, 3rd arg is checked state.
1158 // If 4th arg is present, object_id fields will be updated accordingly to the new state.
1159 // The function returns TRUE if the DB was successfully changed, FALSE otherwise
1160 function processGridForm (&$rackData, $unchecked_state, $checked_state, $object_id = 0)
1161 {
1162 global $loclist, $dbxlink;
1163 $rack_id = $rackData['id'];
1164 $rack_name = $rackData['name'];
1165 $rackchanged = FALSE;
1166 $dbxlink->beginTransaction();
1167 for ($unit_no = $rackData['height']; $unit_no > 0; $unit_no--)
1168 {
1169 for ($locidx = 0; $locidx < 3; $locidx++)
1170 {
1171 if ($rackData[$unit_no][$locidx]['enabled'] != TRUE)
1172 continue;
1173 // detect a change
1174 $state = $rackData[$unit_no][$locidx]['state'];
1175 $newstate = isCheckSet ("atom_${rack_id}_${unit_no}_${locidx}") ? $checked_state : $unchecked_state;
1176 if ($state == $newstate)
1177 continue;
1178 $rackchanged = TRUE;
1179 // and validate
1180 $atom = $loclist[$locidx];
1181 // The only changes allowed are those introduced by checkbox grid.
1182 if
1183 (
1184 !($state == $checked_state && $newstate == $unchecked_state) &&
1185 !($state == $unchecked_state && $newstate == $checked_state)
1186 )
1187 {
1188 showError ("${rack_name}: Rack ID ${rack_id}, unit ${unit_no}, 'atom ${atom}', cannot change state from '${state}' to '${newstate}'");
1189 $dbxlink->rollBack();
1190 return FALSE;
1191 }
1192 // Here we avoid using ON DUPLICATE KEY UPDATE by first performing DELETE
1193 // anyway and then looking for probable need of INSERT.
1194 usePreparedDeleteBlade ('RackSpace', array ('rack_id' => $rack_id, 'unit_no' => $unit_no, 'atom' => $atom));
1195 if ($newstate != 'F')
1196 usePreparedInsertBlade ('RackSpace', array ('rack_id' => $rack_id, 'unit_no' => $unit_no, 'atom' => $atom, 'state' => $newstate));
1197 if ($newstate == 'T' && $object_id != 0)
1198 {
1199 // At this point we already have a record in RackSpace.
1200 usePreparedUpdateBlade
1201 (
1202 'RackSpace',
1203 array ('object_id' => $object_id),
1204 array
1205 (
1206 'rack_id' => $rack_id,
1207 'unit_no' => $unit_no,
1208 'atom' => $atom,
1209 )
1210 );
1211 $rackData[$unit_no][$locidx]['object_id'] = $object_id;
1212 }
1213 }
1214 }
1215 if ($rackchanged)
1216 {
1217 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1218 $dbxlink->commit();
1219 return TRUE;
1220 }
1221 $dbxlink->rollBack();
1222 return FALSE;
1223 }
1224
1225 function updateObjectAllocation ()
1226 {
1227 setFuncMessages (__FUNCTION__, array ('OK' => 63));
1228 global $remote_username;
1229 global $op;
1230 if (!isset ($_REQUEST['got_atoms']))
1231 {
1232 unset($_GET['page']);
1233 unset($_GET['tab']);
1234 unset($_GET['op']);
1235 unset($_POST['page']);
1236 unset($_POST['tab']);
1237 unset($_POST['op']);
1238 return buildRedirectURL (NULL, NULL, $_REQUEST);
1239 }
1240 $object_id = getBypassValue();
1241 $object = spotEntity ('object', $object_id);
1242 $changecnt = 0;
1243 // Get a list of rack ids which are parents of the object
1244 $parentRacks = reduceSubarraysToColumn (getParents ($object, 'rack'), 'id');
1245 $workingRacksData = array();
1246 foreach ($_REQUEST['rackmulti'] as $cand_id)
1247 {
1248 if (!isset ($workingRacksData[$cand_id]))
1249 {
1250 $rackData = spotEntity ('rack', $cand_id);
1251 amplifyCell ($rackData);
1252 $workingRacksData[$cand_id] = $rackData;
1253 }
1254 else
1255 $rackData = $workingRacksData[$cand_id];
1256 $is_ro = ! rackModificationPermitted ($rackData, $op, FALSE);
1257 // It's zero-U mounted to this rack on the form, but not in the DB. Mount it.
1258 if (isset($_REQUEST["zerou_${cand_id}"]) && !in_array($cand_id, $parentRacks))
1259 {
1260 if ($is_ro)
1261 continue;
1262 $changecnt++;
1263 commitLinkEntities ('rack', $cand_id, 'object', $object_id);
1264 }
1265 // It's not zero-U mounted to this rack on the form, but it is in the DB. Unmount it.
1266 if (!isset($_REQUEST["zerou_${cand_id}"]) && in_array($cand_id, $parentRacks))
1267 {
1268 if ($is_ro)
1269 continue;
1270 $changecnt++;
1271 commitUnlinkEntities ('rack', $cand_id, 'object', $object_id);
1272 }
1273 }
1274
1275 foreach (array_keys ($workingRacksData) as $key)
1276 applyObjectMountMask ($workingRacksData[$key], $object_id);
1277
1278 $oldMolecule = getMoleculeForObject ($object_id);
1279 foreach ($workingRacksData as $rack_id => $rackData)
1280 {
1281 $is_ro = ! rackModificationPermitted ($rackData, $op, FALSE);
1282 if ($is_ro || !processGridForm ($rackData, 'F', 'T', $object_id))
1283 continue;
1284 $changecnt++;
1285 // Reload our working copy after form processing.
1286 $rackData = spotEntity ('rack', $cand_id);
1287 amplifyCell ($rackData);
1288 applyObjectMountMask ($rackData, $object_id);
1289 $workingRacksData[$rack_id] = $rackData;
1290 }
1291 if ($changecnt)
1292 {
1293 // Log a record.
1294 $newMolecule = getMoleculeForObject ($object_id);
1295 usePreparedInsertBlade
1296 (
1297 'MountOperation',
1298 array
1299 (
1300 'object_id' => $object_id,
1301 'old_molecule_id' => count ($oldMolecule) ? createMolecule ($oldMolecule) : NULL,
1302 'new_molecule_id' => count ($newMolecule) ? createMolecule ($newMolecule) : NULL,
1303 'user_name' => $remote_username,
1304 'comment' => nullIfEmptyStr (genericAssertion ('comment', 'string0')),
1305 )
1306 );
1307 }
1308 showFuncMessage (__FUNCTION__, 'OK', array ($changecnt));
1309 }
1310
1311 function updateObject ()
1312 {
1313 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1314 $taglist = genericAssertion ('taglist', 'array0');
1315 genericAssertion ('num_attrs', 'uint0');
1316 genericAssertion ('object_name', 'string0');
1317 genericAssertion ('object_label', 'string0');
1318 genericAssertion ('object_asset_no', 'string0');
1319 genericAssertion ('object_comment', 'string0');
1320 $object_type_id = genericAssertion ('object_type_id', 'uint');
1321 $object_id = getBypassValue();
1322
1323 global $dbxlink;
1324 $dbxlink->beginTransaction();
1325 commitUpdateObject
1326 (
1327 $object_id,
1328 $_REQUEST['object_name'],
1329 $_REQUEST['object_label'],
1330 isCheckSet ('object_has_problems', 'yesno'),
1331 $_REQUEST['object_asset_no'],
1332 $_REQUEST['object_comment']
1333 );
1334 updateObjectAttributes ($object_id);
1335 $object = spotEntity ('object', $object_id);
1336 if ($object_type_id != $object['objtype_id'])
1337 {
1338 if (! array_key_exists ($object_type_id, getObjectTypeChangeOptions ($object_id)))
1339 throw new InvalidRequestArgException ('new type_id', $object_type_id, 'incompatible with requested attribute values');
1340 usePreparedUpdateBlade ('Object', array ('objtype_id' => $object_type_id), array ('id' => $object_id));
1341 }
1342 // Invalidate thumb cache of all racks objects could occupy.
1343 foreach (getResidentRacksData ($object_id, FALSE) as $rack_id)
1344 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1345 $dbxlink->commit();
1346 rebuildTagChainForEntity ('object', $object_id, buildTagChainFromIds ($taglist), TRUE);
1347 showFuncMessage (__FUNCTION__, 'OK');
1348 }
1349
1350 // Used when updating an object, location or rack
1351 function updateObjectAttributes ($object_id)
1352 {
1353 $type_id = getObjectType ($object_id);
1354 $oldvalues = getAttrValues ($object_id);
1355 $num_attrs = isset ($_REQUEST['num_attrs']) ? $_REQUEST['num_attrs'] : 0;
1356 for ($i = 0; $i < $num_attrs; $i++)
1357 {
1358 $attr_id = genericAssertion ("${i}_attr_id", 'uint');
1359 if (! array_key_exists ($attr_id, $oldvalues))
1360 throw new InvalidRequestArgException ('attr_id', $attr_id, 'malformed request');
1361 $value = genericAssertion ("${i}_value", 'string0');
1362
1363 // If the object is a rack, skip certain attributes as they are handled elsewhere
1364 // (height, sort_order)
1365 if ($type_id == 1560 && ($attr_id == 27 || $attr_id == 29))
1366 continue;
1367
1368 // Delete attribute and move on, when the field is empty or if the field
1369 // type is a dictionary and it is the "--NOT SET--" value of 0.
1370 if ($value == '' || ($oldvalues[$attr_id]['type'] == 'dict' && $value == 0))
1371 {
1372 if (permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $attr_id))))
1373 commitUpdateAttrValue ($object_id, $attr_id);
1374 else
1375 showError ('Permission denied, "' . $oldvalues[$attr_id]['name'] . '" left unchanged');
1376 continue;
1377 }
1378
1379 // The value could be uint/float, but we don't know ATM. Let SQL
1380 // server check this and complain.
1381 if ('date' == $oldvalues[$attr_id]['type'])
1382 $value = timestampFromDatetimestr (genericAssertion ("${i}_value", 'datetime'));
1383
1384 switch ($oldvalues[$attr_id]['type'])
1385 {
1386 case 'uint':
1387 case 'float':
1388 case 'string':
1389 case 'date':
1390 $oldvalue = $oldvalues[$attr_id]['value'];
1391 break;
1392 case 'dict':
1393 $oldvalue = $oldvalues[$attr_id]['key'];
1394 break;
1395 default:
1396 }
1397 if ($value === $oldvalue) // ('' == 0), but ('' !== 0)
1398 continue;
1399 if (permitted (NULL, NULL, NULL, array (array ('tag' => '$attr_' . $attr_id))))
1400 commitUpdateAttrValue ($object_id, $attr_id, $value);
1401 else
1402 showError ('Permission denied, "' . $oldvalues[$attr_id]['name'] . '" left unchanged');
1403 }
1404 }
1405
1406 function addMultipleObjects()
1407 {
1408 $taglist = genericAssertion ('taglist', 'array0');
1409 $max = genericAssertion ('num_records', 'uint');
1410 for ($i = 0; $i < $max; $i++)
1411 {
1412 $tid = genericAssertion ("${i}_object_type_id", 'uint0');
1413 assertStringArg ("${i}_object_name", TRUE);
1414 assertStringArg ("${i}_object_label", TRUE);
1415 assertStringArg ("${i}_object_asset_no", TRUE);
1416 $name = $_REQUEST["${i}_object_name"];
1417
1418 if ($tid == 0)
1419 continue; // Just skip on intact SELECT.
1420 try
1421 {
1422 $object_id = commitAddObject
1423 (
1424 $name,
1425 $_REQUEST["${i}_object_label"],
1426 $tid,
1427 $_REQUEST["${i}_object_asset_no"],
1428 $taglist
1429 );
1430 showSuccess ('added object ' . mkCellA (spotEntity ('object', $object_id)));
1431 }
1432 catch (RTDatabaseError $e)
1433 {
1434 showError ("Error creating object '$name': " . $e->getMessage());
1435 }
1436 }
1437 }
1438
1439 function addLotOfObjects()
1440 {
1441 $taglist = genericAssertion ('taglist', 'array0');
1442 assertStringArg ('namelist', TRUE);
1443 $global_type_id = genericAssertion ('global_type_id', 'uint0');
1444 if ($global_type_id == 0 || $_REQUEST['namelist'] == '')
1445 {
1446 showError ('Incomplete form has been ignored. Cheers.');
1447 return;
1448 }
1449 foreach (textareaCooked ($_REQUEST['namelist']) as $name)
1450 try
1451 {
1452 $object_id = commitAddObject ($name, NULL, $global_type_id, '', $taglist);
1453 showSuccess ('added object ' . mkCellA (spotEntity ('object', $object_id)));
1454 }
1455 catch (RackTablesError $e)
1456 {
1457 showError ("Failed to add object '$name': " . $e->getMessage());
1458 }
1459 }
1460
1461 function linkObjects ()
1462 {
1463 commitLinkEntities
1464 (
1465 genericAssertion ('parent_entity_type', 'string'),
1466 genericAssertion ('parent_entity_id', 'uint'),
1467 genericAssertion ('child_entity_type', 'string'),
1468 genericAssertion ('child_entity_id', 'uint')
1469 );
1470 showSuccess ('Container set successfully');
1471 }
1472
1473 function deleteObject ()
1474 {
1475 setFuncMessages (__FUNCTION__, array ('OK' => 7));
1476 $oinfo = spotEntity ('object', genericAssertion ('object_id', 'uint'));
1477
1478 $racklist = getResidentRacksData ($oinfo['id'], FALSE);
1479 commitDeleteObject ($oinfo['id']);
1480 foreach ($racklist as $rack_id)
1481 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1482 showFuncMessage (__FUNCTION__, 'OK', array ($oinfo['dname']));
1483 }
1484
1485 function resetObject ()
1486 {
1487 setFuncMessages (__FUNCTION__, array ('OK' => 57));
1488 $racklist = getResidentRacksData (getBypassValue(), FALSE);
1489 commitResetObject (getBypassValue());
1490 foreach ($racklist as $rack_id)
1491 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
1492 showFuncMessage (__FUNCTION__, 'OK');
1493 }
1494
1495 function updateUI ()
1496 {
1497 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1498 $num_vars = genericAssertion ('num_vars', 'uint');
1499 try
1500 {
1501 for ($i = 0; $i < $num_vars; $i++)
1502 {
1503 assertStringArg ("${i}_varvalue", TRUE);
1504 $varname = genericAssertion ("${i}_varname", 'string');
1505 $varvalue = $_REQUEST["${i}_varvalue"];
1506 // If form value = value in DB, don't bother updating DB.
1507 if (isConfigVarChanged ($varname, $varvalue))
1508 setConfigVar ($varname, $varvalue);
1509 }
1510 }
1511 catch (InvalidArgException $iae)
1512 {
1513 throw $iae->newIRAE();
1514 }
1515 showFuncMessage (__FUNCTION__, 'OK');
1516 }
1517
1518 function saveMyPreferences ()
1519 {
1520 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1521 $num_vars = genericAssertion ('num_vars', 'uint');
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
1529 // If form value = value in DB, don't bother updating DB
1530 if (!isConfigVarChanged($varname, $varvalue))
1531 continue;
1532 try
1533 {
1534 setUserConfigVar ($varname, $varvalue);
1535 }
1536 catch (InvalidArgException $iae)
1537 {
1538 throw $iae->newIRAE();
1539 }
1540 }
1541 showFuncMessage (__FUNCTION__, 'OK');
1542 }
1543
1544 function resetMyPreference ()
1545 {
1546 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1547 try
1548 {
1549 resetUserConfigVar (genericAssertion ('varname', 'string'));
1550 }
1551 catch (InvalidArgException $iae)
1552 {
1553 throw $iae->newIRAE();
1554 }
1555 showFuncMessage (__FUNCTION__, 'OK');
1556 }
1557
1558 // FIXME: Move the default values to dictionary.php and feed from there into
1559 // this function and the installer to avoid duplication.
1560 function resetUIConfig()
1561 {
1562 setFuncMessages (__FUNCTION__, array ('OK' => 57));
1563 $defaults = array
1564 (
1565 'MASSCOUNT' => '8',
1566 'MAXSELSIZE' => '30',
1567 'ROW_SCALE' => '2',
1568 'IPV4_ADDRS_PER_PAGE' => '256',
1569 'DEFAULT_RACK_HEIGHT' => '42',
1570 'DEFAULT_SLB_VS_PORT' => '',
1571 'DEFAULT_SLB_RS_PORT' => '',
1572 'DETECT_URLS' => 'no',
1573 'RACK_PRESELECT_THRESHOLD' => '1',
1574 'DEFAULT_IPV4_RS_INSERVICE' => 'no',
1575 'AUTOPORTS_CONFIG' => '4 = 1*33*kvm + 2*24*eth%u;15 = 1*446*kvm',
1576 'SHOW_EXPLICIT_TAGS' => 'yes',
1577 'SHOW_IMPLICIT_TAGS' => 'yes',
1578 'SHOW_AUTOMATIC_TAGS' => 'no',
1579 'DEFAULT_OBJECT_TYPE' => '4',
1580 'IPV4_AUTO_RELEASE' => '1',
1581 'SHOW_LAST_TAB' => 'yes',
1582 'EXT_IPV4_VIEW' => 'yes',
1583 'TREE_THRESHOLD' => '25',
1584 'IPV4_JAYWALK' => 'no',
1585 'ADDNEW_AT_TOP' => 'yes',
1586 'IPV4_TREE_SHOW_USAGE' => 'no',
1587 'PREVIEW_TEXT_MAXCHARS' => '10240',
1588 'PREVIEW_TEXT_ROWS' => '25',
1589 'PREVIEW_TEXT_COLS' => '80',
1590 'PREVIEW_IMAGE_MAXPXS' => '320',
1591 'VENDOR_SIEVE' => '',
1592 'IPV4LB_LISTSRC' => 'false',
1593 'IPV4OBJ_LISTSRC' => 'not ({$typeid_3} or {$typeid_9} or {$typeid_10} or {$typeid_11})',
1594 'IPV4NAT_LISTSRC' => '{$typeid_4} or {$typeid_7} or {$typeid_8} or {$typeid_798}',
1595 'ASSETWARN_LISTSRC' => '{$typeid_4} or {$typeid_7} or {$typeid_8}',
1596 'NAMEWARN_LISTSRC' => '{$typeid_4} or {$typeid_7} or {$typeid_8}',
1597 'RACKS_PER_ROW' => '12',
1598 'FILTER_PREDICATE_SIEVE' => '',
1599 'FILTER_DEFAULT_ANDOR' => 'and',
1600 'FILTER_SUGGEST_ANDOR' => 'yes',
1601 'FILTER_SUGGEST_TAGS' => 'yes',
1602 'FILTER_SUGGEST_PREDICATES' => 'yes',
1603 'FILTER_SUGGEST_EXTRA' => 'no',
1604 'DEFAULT_SNMP_COMMUNITY' => 'public',
1605 'IPV4_ENABLE_KNIGHT' => 'yes',
1606 'TAGS_TOPLIST_SIZE' => '50',
1607 'TAGS_QUICKLIST_SIZE' => '20',
1608 'TAGS_QUICKLIST_THRESHOLD' => '50',
1609 'ENABLE_MULTIPORT_FORM' => 'no',
1610 'DEFAULT_PORT_IIF_ID' => '1',
1611 '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',
1612 'IPV4_TREE_RTR_AS_CELL' => 'no',
1613 'PROXIMITY_RANGE' => '0',
1614 'IPV4_TREE_SHOW_VLAN' => 'yes',
1615 'VLANSWITCH_LISTSRC' => '',
1616 'VLANIPV4NET_LISTSRC' => '',
1617 'DEFAULT_VDOM_ID' => '',
1618 'DEFAULT_VST_ID' => '',
1619 'STATIC_FILTER' => 'yes',
1620 '8021Q_DEPLOY_MINAGE' => '300',
1621 '8021Q_DEPLOY_MAXAGE' => '3600',
1622 '8021Q_DEPLOY_RETRY' => '10800',
1623 '8021Q_WRI_AFTER_CONFT_LISTSRC' => 'false',
1624 '8021Q_INSTANT_DEPLOY' => 'no',
1625 'CDP_RUNNERS_LISTSRC' => '',
1626 'LLDP_RUNNERS_LISTSRC' => '',
1627 'SHRINK_TAG_TREE_ON_CLICK' => 'yes',
1628 'MAX_UNFILTERED_ENTITIES' => '0',
1629 'SYNCDOMAIN_MAX_PROCESSES' => '0',
1630 'PORT_EXCLUSION_LISTSRC' => '{$typeid_3} or {$typeid_10} or {$typeid_11} or {$typeid_1505} or {$typeid_1506}',
1631 'FILTER_RACKLIST_BY_TAGS' => 'yes',
1632 'MGMT_PROTOS' => 'ssh: {$typeid_4}; telnet: {$typeid_8}',
1633 'SYNC_8021Q_LISTSRC' => '',
1634 'QUICK_LINK_PAGES' => 'depot,ipv4space,rackspace',
1635 'CACTI_LISTSRC' => 'false',
1636 'CACTI_RRA_ID' => '1',
1637 'MUNIN_LISTSRC' => 'false',
1638 'VIRTUAL_OBJ_LISTSRC' => '1504,1505,1506,1507',
1639 'DATETIME_ZONE' => 'UTC',
1640 'DATETIME_FORMAT' => '%Y-%m-%d',
1641 'SEARCH_DOMAINS' => '',
1642 '8021Q_EXTSYNC_LISTSRC' => 'false',
1643 '8021Q_MULTILINK_LISTSRC' => 'false',
1644 'REVERSED_RACKS_LISTSRC' => 'false',
1645 'NEAREST_RACKS_CHECKBOX' => 'yes',
1646 'SHOW_OBJECTTYPE' => 'yes',
1647 'IPV4_TREE_SHOW_UNALLOCATED' => 'yes',
1648 );
1649 foreach ($defaults as $name => $value)
1650 setConfigVar ($name, $value);
1651 showFuncMessage (__FUNCTION__, 'OK');
1652 }
1653
1654 // Add single record.
1655 function addRealServer ()
1656 {
1657 setFuncMessages (__FUNCTION__, array ('OK' => 48));
1658 addRStoRSPool
1659 (
1660 getBypassValue(),
1661 genericAssertion ('rsip', 'inet'),
1662 genericAssertion ('rsport', 'string0'),
1663 isCheckSet ('inservice', 'yesno'),
1664 genericAssertion ('rsconfig', 'string0'),
1665 genericAssertion ('comment', 'string0')
1666 );
1667 showFuncMessage (__FUNCTION__, 'OK');
1668 }
1669
1670 // Parse textarea submitted and try adding a real server for each line.
1671 function addRealServers ()
1672 {
1673 setFuncMessages (__FUNCTION__, array ('OK' => 37, 'ERR1' => 131));
1674 $format = genericAssertion ('format', 'string');
1675 $ngood = 0;
1676 // Keep in mind, that the text will have HTML entities (namely '>') escaped.
1677 foreach (explode ("\n", dos2unix (genericAssertion ('rawtext', 'string'))) as $line)
1678 {
1679 if ($line == '')
1680 continue;
1681 $match = array ();
1682 switch ($format)
1683 {
1684 case 'ipvs_2': // address and port only
1685 if (!preg_match ('/^ -> ([0-9\.]+):([0-9]+) /', $line, $match))
1686 if (!preg_match ('/^ -> \[([0-9a-fA-F:]+)\]:([0-9]+) /', $line, $match))
1687 continue;
1688 addRStoRSPool (getBypassValue(), ip_parse ($match[1]), $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), '');
1689 break;
1690 case 'ipvs_3': // address, port and weight
1691 if (!preg_match ('/^ -> ([0-9\.]+):([0-9]+) +[a-zA-Z]+ +([0-9]+) /', $line, $match))
1692 if (!preg_match ('/^ -> \[([0-9a-fA-F:]+)\]:([0-9]+) +[a-zA-Z]+ +([0-9]+) /', $line, $match))
1693 continue;
1694 addRStoRSPool (getBypassValue(), ip_parse ($match[1]), $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), 'weight ' . $match[3]);
1695 break;
1696 case 'ssv_2': // IP address and port
1697 if (!preg_match ('/^([0-9\.a-fA-F:]+) ([0-9]+)$/', $line, $match))
1698 continue;
1699 addRStoRSPool (getBypassValue(), ip_parse ($match[1]), $match[2], getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), '');
1700 break;
1701 case 'ssv_1': // IP address
1702 if (! $ip_bin = ip_checkparse ($line))
1703 continue;
1704 addRStoRSPool (getBypassValue(), $ip_bin, 0, getConfigVar ('DEFAULT_IPV4_RS_INSERVICE'), '');
1705 break;
1706 default:
1707 showFuncMessage (__FUNCTION__, 'ERR1');
1708 return;
1709 }
1710 $ngood++;
1711 }
1712 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
1713 }
1714
1715 function addVService ()
1716 {
1717 assertStringArg ('name', TRUE);
1718 $proto = genericAssertion ('proto', 'enum/ipproto');
1719 usePreparedInsertBlade
1720 (
1721 'IPv4VS',
1722 array
1723 (
1724 'vip' => genericAssertion ('vip', 'inet'),
1725 'vport' => $proto == 'MARK' ? NULL : genericAssertion ('vport', 'uint'),
1726 'proto' => $proto,
1727 'name' => nullIfEmptyStr ($_REQUEST['name']),
1728 'vsconfig' => nullIfEmptyStr (genericAssertion ('vsconfig', 'string0')),
1729 'rsconfig' => nullIfEmptyStr (genericAssertion ('rsconfig', 'string0')),
1730 )
1731 );
1732 $vs_id = lastInsertID();
1733 lastCreated ('ipv4vs', $vs_id);
1734 if (isset ($_REQUEST['taglist']))
1735 produceTagsForNewRecord ('ipv4vs', genericAssertion ('taglist', 'array0'), $vs_id);
1736 $vsinfo = spotEntity ('ipv4vs', $vs_id);
1737 showSuccess (mkCellA ($vsinfo) . ' created successfully');
1738 }
1739
1740 function addVSG ()
1741 {
1742 $name = assertStringArg ('name');
1743 usePreparedInsertBlade ('VS', array ('name' => $name));
1744 $vs_id = lastInsertID();
1745 lastCreated ('ipvs', $vs_id);
1746 if (isset ($_REQUEST['taglist']))
1747 produceTagsForNewRecord ('ipvs', $_REQUEST['taglist'], $vs_id);
1748 $vsinfo = spotEntity ('ipvs', $vs_id);
1749 showSuccess (mkCellA ($vsinfo) . ' created successfully');
1750 }
1751
1752 function deleteVService ()
1753 {
1754 setFuncMessages (__FUNCTION__, array ('OK' => 49));
1755 $vsinfo = spotEntity ('ipv4vs', genericAssertion ('vs_id', 'uint'));
1756 if ($vsinfo['refcnt'] != 0)
1757 {
1758 showError ("Could not delete linked virtual service");
1759 return;
1760 }
1761 commitDeleteVS ($vsinfo['id']);
1762 showFuncMessage (__FUNCTION__, 'OK');
1763 return buildRedirectURL ('ipv4slb', 'default');
1764 }
1765
1766 function deleteVS()
1767 {
1768 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1769 if (count (getTriplets ($vsinfo)) != 0)
1770 {
1771 showError ("Could not delete linked virtual service group");
1772 return;
1773 }
1774 commitDeleteVSG ($vsinfo['id']);
1775 showSuccess (formatEntityName ($vsinfo) . ' deleted');
1776 return buildRedirectURL ('ipv4slb', 'vs');
1777 }
1778
1779 function updateSLBDefConfig ()
1780 {
1781 setFuncMessages (__FUNCTION__, array ('OK' => 43));
1782 commitUpdateSLBDefConf
1783 (
1784 array
1785 (
1786 'vs' => genericAssertion ('vsconfig', 'string0'),
1787 'rs' => genericAssertion ('rsconfig', 'string0'),
1788 )
1789 );
1790 showFuncMessage (__FUNCTION__, 'OK');
1791 }
1792
1793 function updateRealServer ()
1794 {
1795 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1796 commitUpdateRS (
1797 genericAssertion ('rs_id', 'uint'),
1798 genericAssertion ('rsip', 'inet'),
1799 genericAssertion ('rsport', 'string0'),
1800 isCheckSet ('inservice', 'yesno'),
1801 genericAssertion ('rsconfig', 'string0'),
1802 genericAssertion ('comment', 'string0')
1803 );
1804 showFuncMessage (__FUNCTION__, 'OK');
1805 }
1806
1807 function updateVService ()
1808 {
1809 setFuncMessages (__FUNCTION__, array ('OK' => 51));
1810 $vs_id = getBypassValue();
1811 $taglist = genericAssertion ('taglist', 'array0');
1812 $proto = genericAssertion ('proto', 'enum/ipproto');
1813 genericAssertion ('vport', $proto == 'MARK' ? 'string0' : 'uint');
1814 assertStringArg ('name', TRUE);
1815 commitUpdateVS (
1816 $vs_id,
1817 genericAssertion ('vip', 'inet'),
1818 $_REQUEST['vport'],
1819 $proto,
1820 $_REQUEST['name'],
1821 genericAssertion ('vsconfig', 'string0'),
1822 genericAssertion ('rsconfig', 'string0')
1823 );
1824 rebuildTagChainForEntity ('ipvs', $vs_id, buildTagChainFromIds ($taglist), TRUE);
1825 showFuncMessage (__FUNCTION__, 'OK');
1826 }
1827
1828 function updateVS ()
1829 {
1830 $taglist = genericAssertion ('taglist', 'array0');
1831 $vs_id = assertUIntArg ('vs_id');
1832 $name = assertStringArg ('name');
1833 $vsconfig = nullIfEmptyStr (assertStringArg ('vsconfig', TRUE));
1834 $rsconfig = nullIfEmptyStr (assertStringArg ('rsconfig', TRUE));
1835
1836 usePreparedUpdateBlade ('VS', array ('name' => $name, 'vsconfig' => $vsconfig, 'rsconfig' => $rsconfig), array ('id' => $vs_id));
1837 rebuildTagChainForEntity ('ipvs', $vs_id, buildTagChainFromIds ($taglist), TRUE);
1838 showSuccess ("Service updated successfully");
1839 }
1840
1841 function addIPToVS()
1842 {
1843 $ip_bin = assertIPArg ('ip');
1844 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1845 amplifyCell ($vsinfo);
1846 $row = array ('vs_id' => $vsinfo['id'], 'vip' => $ip_bin, 'vsconfig' => NULL, 'rsconfig' => NULL);
1847 if ($vip = isVIPEnabled ($row, $vsinfo['vips']))
1848 {
1849 showError ("Service already contains IP " . formatVSIP ($vip));
1850 return;
1851 }
1852 usePreparedInsertBlade ('VSIPs', $row);
1853 showSuccess ("IP addded");
1854 }
1855
1856 function addPortToVS()
1857 {
1858 $proto = genericAssertion ('proto', 'enum/ipproto');
1859 $vport = assertUIntArg ('port', TRUE);
1860 if ($proto == 'MARK')
1861 {
1862 if ($vport > 0xFFFFFFFF)
1863 {
1864 showError ("fwmark value is too large");
1865 return;
1866 }
1867 }
1868 else
1869 if ($vport == 0 || $vport >= 0xFFFF)
1870 {
1871 showError ("Invalid $proto port value");
1872 return;
1873 }
1874
1875 $vsinfo = spotEntity ('ipvs', getBypassValue());
1876 amplifyCell ($vsinfo);
1877 $row = array ('vs_id' => $vsinfo['id'], 'proto' => $proto, 'vport' => $vport, 'vsconfig' => NULL, 'rsconfig' => NULL);
1878 if ($port = isPortEnabled ($row, $vsinfo['ports']))
1879 {
1880 showError ("Service already contains port " . $port['proto'] . ' ' . $port['vport']);
1881 return;
1882 }
1883 usePreparedInsertBlade ('VSPorts', $row);
1884 showSuccess ("port addded");
1885 }
1886
1887 function updateIPInVS()
1888 {
1889 $vs_id = assertUIntArg ('vs_id');
1890 $ip_bin = assertIPArg ('ip');
1891 $vsconfig = nullIfEmptyStr (assertStringArg ('vsconfig', TRUE));
1892 $rsconfig = nullIfEmptyStr (assertStringArg ('rsconfig', TRUE));
1893 if (usePreparedUpdateBlade ('VSIPs', array ('vsconfig' => $vsconfig, 'rsconfig' => $rsconfig), array ('vs_id' => $vs_id, 'vip' => $ip_bin)))
1894 showSuccess ("IP configuration updated");
1895 else
1896 showNotice ("Nothing changed");
1897 }
1898
1899 function updatePortInVS()
1900 {
1901 $vs_id = assertUIntArg ('vs_id');
1902 $proto = assertStringArg ('proto');
1903 $vport = assertUIntArg ('port', TRUE);
1904 $vsconfig = nullIfEmptyStr (assertStringArg ('vsconfig', TRUE));
1905 $rsconfig = nullIfEmptyStr (assertStringArg ('rsconfig', TRUE));
1906 if (usePreparedUpdateBlade ('VSPorts', array ('vsconfig' => $vsconfig, 'rsconfig' => $rsconfig), array ('vs_id' => $vs_id, 'proto' => $proto, 'vport' => $vport)))
1907 showSuccess ("Port configuration updated");
1908 else
1909 showNotice ("Nothing changed");
1910 }
1911
1912 function removeIPFromVS()
1913 {
1914 $vip = array ('vip' => assertIPArg ('ip'));
1915 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1916 amplifyCell ($vsinfo);
1917 $used = 0;
1918 foreach (getTriplets ($vsinfo) as $triplet)
1919 if (isVIPEnabled ($vip, $triplet['vips']))
1920 $used++;
1921 if (usePreparedDeleteBlade ('VSIPs', array ('vs_id' => $vsinfo['id']) + $vip))
1922 showSuccess ("IP removed" . ($used ? ", it was binded with $used SLBs" : ''));
1923 else
1924 showNotice ("Nothing changed");
1925 }
1926
1927 function removePortFromVS()
1928 {
1929 $port = array ('proto' => assertStringArg ('proto'), 'vport' => assertUIntArg ('port', TRUE));
1930 $vsinfo = spotEntity ('ipvs', assertUIntArg ('vs_id'));
1931 amplifyCell ($vsinfo);
1932 $used = 0;
1933 foreach (getTriplets ($vsinfo) as $triplet)
1934 if (isPortEnabled ($port, $triplet['ports']))
1935 $used++;
1936 if (usePreparedDeleteBlade ('VSPorts', array ('vs_id' => $vsinfo['id']) + $port))
1937 showSuccess ("Port removed" . ($used ? ", it was binded with $used SLBs" : ''));
1938 else
1939 showNotice ("Nothing changed");
1940 }
1941
1942 function updateTripletConfig()
1943 {
1944 global $op;
1945 $key_fields = array
1946 (
1947 'object_id' => assertUIntArg ('object_id'),
1948 'vs_id' => assertUIntArg ('vs_id'),
1949 'rspool_id' => assertUIntArg ('rspool_id'),
1950 );
1951 $config_fields = array
1952 (
1953 'vsconfig' => nullIfEmptyStr (assertStringArg ('vsconfig', TRUE)),
1954 'rsconfig' => nullIfEmptyStr (assertStringArg ('rsconfig', TRUE)),
1955 );
1956
1957 $vsinfo = spotEntity ('ipvs', $key_fields['vs_id']);
1958 amplifyCell ($vsinfo);
1959 $found = FALSE;
1960
1961 if ($op == 'updPort')
1962 {
1963 $table = 'VSEnabledPorts';
1964 $proto = assertStringArg ('proto');
1965 $vport = assertUIntArg ('port', TRUE);
1966 $key_fields['proto'] = $proto;
1967 $key_fields['vport'] = $vport;
1968 $key = "Port $proto-$vport";
1969 // check if such port exists in VS
1970 foreach ($vsinfo['ports'] as $vs_port)
1971 if ($vs_port['proto'] == $proto && $vs_port['vport'] == $vport)
1972 {
1973 $found = TRUE;
1974 break;
1975 }
1976 }
1977 else
1978 {
1979 $table = 'VSEnabledIPs';
1980 $vip = assertIPArg ('vip');
1981 $config_fields['prio'] = nullIfEmptyStr (assertStringArg ('prio', TRUE));
1982 $key_fields['vip'] = $vip;
1983 $key = "IP " . ip_format ($vip);
1984 // check if such VIP exists in VS
1985 foreach ($vsinfo['vips'] as $vs_vip)
1986 if ($vs_vip['vip'] === $vip)
1987 {
1988 $found = TRUE;
1989 break;
1990 }
1991 }
1992 if (! $found)
1993 {
1994 showError ("$key not found in VS");
1995 return;
1996 }
1997
1998 $nchanged = 0;
1999 if (! isCheckSet ('enabled'))
2000 {
2001 if ($nchanged += usePreparedDeleteBlade ($table, $key_fields))
2002 {
2003 showSuccess ("$key disabled");
2004 return;
2005 }
2006 }
2007 else
2008 {
2009 global $dbxlink;
2010 $dbxlink->beginTransaction();
2011 $q = "SELECT * FROM $table WHERE";
2012 $sep = '';
2013 $params = array();
2014 foreach ($key_fields as $field => $value)
2015 {
2016 $q .= " $sep $field = ?";
2017 $params[] = $value;
2018 $sep = 'AND';
2019 }
2020 $result = usePreparedSelectBlade ("$q FOR UPDATE", $params);
2021 $row = $result->fetch (PDO::FETCH_ASSOC);
2022 unset ($result);
2023 if ($row)
2024 {
2025 if ($nchanged += usePreparedUpdateBlade ($table, $config_fields, $key_fields))
2026 showSuccess ("$key config updated");
2027 }
2028 else
2029 {
2030 if (
2031 $nchanged += ($table == 'VSEnabledIPs' ?
2032 addSLBIPLink ($key_fields + $config_fields) :
2033 addSLBPortLink ($key_fields + $config_fields)
2034 )
2035 )
2036 showSuccess ("$key enabled");
2037 }
2038 $dbxlink->commit();
2039 }
2040 if (! $nchanged)
2041 showNotice ("No changes made");
2042 }
2043
2044 function removeTriplet()
2045 {
2046 $key_fields = array
2047 (
2048 'object_id' => assertUIntArg ('object_id'),
2049 'vs_id' => assertUIntArg ('vs_id'),
2050 'rspool_id' => assertUIntArg ('rspool_id'),
2051 );
2052
2053 global $dbxlink;
2054 $dbxlink->beginTransaction();
2055 usePreparedDeleteBlade ('VSEnabledIPs', $key_fields);
2056 usePreparedDeleteBlade ('VSEnabledPorts', $key_fields);
2057 $dbxlink->commit();
2058 showSuccess ('Triplet deleted');
2059 }
2060
2061 function createTriplet()
2062 {
2063 global $dbxlink;
2064 $object_id = assertUIntArg ('object_id');
2065 $vs_id = assertUIntArg ('vs_id');
2066 $rspool_id = assertUIntArg ('rspool_id');
2067 $vips = genericAssertion ('enabled_vips', 'array0');
2068 $ports = genericAssertion ('enabled_ports', 'array0');
2069
2070 $vsinfo = spotEntity ('ipvs', $vs_id);
2071 amplifyCell ($vsinfo);
2072 try
2073 {
2074 $dbxlink->beginTransaction();
2075 foreach ($vsinfo['vips'] as $vip)
2076 if (in_array (ip_format ($vip['vip']), $vips))
2077 addSLBIPLink (array ('object_id' => $object_id, 'vs_id' => $vs_id, 'rspool_id' => $rspool_id, 'vip' => $vip['vip']));
2078 foreach ($vsinfo['ports'] as $port)
2079 if (in_array($port['proto'] . '-' . $port['vport'], $ports))
2080 addSLBPortLink (array ('object_id' => $object_id, 'vs_id' => $vs_id, 'rspool_id' => $rspool_id, 'proto' => $port['proto'], 'vport' => $port['vport']));
2081 $dbxlink->commit();
2082 }
2083 catch (RTDatabaseError $e)
2084 {
2085 $dbxlink->rollBack();
2086 throw $e;
2087 }
2088 showSuccess ("SLB triplet created");
2089 }
2090
2091 function addLoadBalancer ()
2092 {
2093 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2094 assertStringArg ('prio', TRUE);
2095
2096 addLBtoRSPool (
2097 genericAssertion ('pool_id', 'uint'),
2098 genericAssertion ('object_id', 'uint'),
2099 genericAssertion ('vs_id', 'uint'),
2100 genericAssertion ('vsconfig', 'string0'),
2101 genericAssertion ('rsconfig', 'string0'),
2102 $_REQUEST['prio']
2103 );
2104 showFuncMessage (__FUNCTION__, 'OK');
2105 }
2106
2107 function addRSPool ()
2108 {
2109 assertStringArg ('name');
2110 $pool_id = commitCreateRSPool
2111 (
2112 $_REQUEST['name'],
2113 genericAssertion ('vsconfig', 'string0'),
2114 genericAssertion ('rsconfig', 'string0'),
2115 isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array()
2116 );
2117 showSuccess ('RS pool ' . mkA ($_REQUEST['name'], 'ipv4rspool', $pool_id) . ' created successfully');
2118 }
2119
2120 function deleteRSPool ()
2121 {
2122 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2123 $poolinfo = spotEntity ('ipv4rspool', genericAssertion ('pool_id', 'uint'));
2124 if ($poolinfo['refcnt'] != 0)
2125 {
2126 showError ("Could not delete linked RS pool");
2127 return;
2128 }
2129 commitDeleteRSPool ($poolinfo['id']);
2130 showFuncMessage (__FUNCTION__, 'OK');
2131 return buildRedirectURL ('ipv4slb', 'rspools');
2132 }
2133
2134 function importPTRData ()
2135 {
2136 setFuncMessages (__FUNCTION__, array ('OK' => 26, 'ERR' => 141));
2137 $net = spotEntity ('ipv4net', getBypassValue());
2138 $addrcount = genericAssertion ('addrcount', 'uint');
2139 $nbad = $ngood = 0;
2140 for ($i = 1; $i <= $addrcount; $i++)
2141 {
2142 $inputname = "import_${i}";
2143 if (! isCheckSet ($inputname))
2144 continue;
2145 $ip_bin = assertIPv4Arg ("addr_${i}");
2146 assertStringArg ("descr_${i}", TRUE);
2147 assertStringArg ("rsvd_${i}");
2148 // Non-existent addresses will not have this argument set in request.
2149 $rsvd = 'no';
2150 if ($_REQUEST["rsvd_${i}"] == 'yes')
2151 $rsvd = 'yes';
2152 try
2153 {
2154 if (! ip_in_range ($ip_bin, $net))
2155 throw new InvalidArgException ('ip_bin', $ip_bin);
2156 updateAddress ($ip_bin, $_REQUEST["descr_${i}"], $rsvd);
2157 $ngood++;
2158 }
2159 catch (RackTablesError $e)
2160 {
2161 $nbad++;
2162 }
2163 }
2164 if (!$nbad)
2165 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
2166 else
2167 showFuncMessage (__FUNCTION__, 'ERR', array ($nbad, $ngood));
2168 }
2169
2170 function generateAutoPorts ()
2171 {
2172 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2173 $object = spotEntity ('object', getBypassValue());
2174 executeAutoPorts ($object['id']);
2175 showFuncMessage (__FUNCTION__, 'OK');
2176 return buildRedirectURL (NULL, 'ports');
2177 }
2178
2179 function updateTag ()
2180 {
2181 try
2182 {
2183 commitUpdateTag
2184 (
2185 genericAssertion ('tag_id', 'uint'),
2186 genericAssertion ('tag_name', 'tag'),
2187 genericAssertion ('parent_id', 'uint0'),
2188 genericAssertion ('is_assignable', 'enum/yesno')
2189 );
2190 }
2191 catch (InvalidArgException $iae)
2192 {
2193 throw $iae->newIRAE();
2194 }
2195 showSuccess ('Tag updated successfully');
2196 }
2197
2198 function saveEntityTags ()
2199 {
2200 setFuncMessages (__FUNCTION__, array ('OK' => 43));
2201 $realm = etypeByPageno();
2202 $entity_id = getBypassValue();
2203 $taglist = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2204 rebuildTagChainForEntity ($realm, $entity_id, buildTagChainFromIds ($taglist), TRUE);
2205 showFuncMessage (__FUNCTION__, 'OK');
2206 }
2207
2208 function rollTags ()
2209 {
2210 setFuncMessages (__FUNCTION__, array ('OK' => 67, 'ERR' => 149));
2211 if (genericAssertion ('sum', 'string0') != genericAssertion ('realsum', 'uint'))
2212 {
2213 showFuncMessage (__FUNCTION__, 'ERR');
2214 return;
2215 }
2216 // Even if the user requested an empty tag list, don't bail out, but process existing
2217 // tag chains with "zero" extra. This will make sure, that the stuff processed will
2218 // have its chains refined to "normal" form.
2219 $extratags = isset ($_REQUEST['taglist']) ? $_REQUEST['taglist'] : array();
2220 $n_ok = 0;
2221 // Minimizing the extra chain early, so that tag rebuilder doesn't have to
2222 // filter out the same tag again and again. It will have own noise to cancel.
2223 $extrachain = getExplicitTagsOnly (buildTagChainFromIds ($extratags));
2224 foreach (listCells ('rack', getBypassValue()) as $rack)
2225 {
2226 if (rebuildTagChainForEntity ('rack', $rack['id'], $extrachain))
2227 $n_ok++;
2228 amplifyCell ($rack);
2229 foreach ($rack['mountedObjects'] as $object_id)
2230 if (rebuildTagChainForEntity ('object', $object_id, $extrachain))
2231 $n_ok++;
2232 }
2233 showFuncMessage (__FUNCTION__, 'OK', array ($n_ok));
2234 }
2235
2236 function changeMyPassword ()
2237 {
2238 setFuncMessages (__FUNCTION__, array ('OK' => 51, 'ERR1' => 150, 'ERR2' => 151, 'ERR3' => 152));
2239 global $remote_username, $user_auth_src;
2240 if ($user_auth_src != 'database')
2241 {
2242 showFuncMessage (__FUNCTION__, 'ERR1');
2243 return;
2244 }
2245 assertStringArg ('oldpassword');
2246 assertStringArg ('newpassword1');
2247 assertStringArg ('newpassword2');
2248 $remote_userid = getUserIDByUsername ($remote_username);
2249 $userinfo = spotEntity ('user', $remote_userid);
2250 if ($userinfo['user_password_hash'] != sha1 ($_REQUEST['oldpassword']))
2251 {
2252 showFuncMessage (__FUNCTION__, 'ERR2');
2253 return;
2254 }
2255 if ($_REQUEST['newpassword1'] != $_REQUEST['newpassword2'])
2256 {
2257 showFuncMessage (__FUNCTION__, 'ERR3');
2258 return;
2259 }
2260 commitUpdateUserAccount ($remote_userid, $userinfo['user_name'], $userinfo['user_realname'], sha1 ($_REQUEST['newpassword1']));
2261 showFuncMessage (__FUNCTION__, 'OK');
2262 }
2263
2264 function saveRackCode ()
2265 {
2266 setFuncMessages (__FUNCTION__, array ('OK' => 43, 'ERR1' => 154));
2267 assertStringArg ('rackcode');
2268 // For the test to succeed, unescape LFs, strip CRs.
2269 $newcode = dos2unix ($_REQUEST['rackcode']);
2270 $parseTree = getRackCode ($newcode);
2271 if ($parseTree['result'] != 'ACK')
2272 {
2273 showFuncMessage (__FUNCTION__, 'ERR1', array ($parseTree['load']));
2274 return;
2275 }
2276 saveScript ('RackCode', $newcode);
2277 saveScript ('RackCodeCache', base64_encode (serialize ($parseTree)));
2278 showFuncMessage (__FUNCTION__, 'OK');
2279 }
2280
2281 function submitSLBConfig ()
2282 {
2283 showNotice ("You should redefine submitSLBConfig ophandler in your local extension to install SLB config");
2284 }
2285
2286 function addLocation ()
2287 {
2288 setFuncMessages (__FUNCTION__, array ('OK' => 5));
2289 assertStringArg ('name');
2290
2291 $location_id = commitAddObject ($_REQUEST['name'], NULL, 1562, NULL);
2292 if (0 != $parent_id = genericAssertion ('parent_id', 'uint0'))
2293 commitLinkEntities ('location', $parent_id, 'location', $location_id);
2294 showSuccess ('added location ' . mkA ($_REQUEST['name'], 'location', $location_id));
2295 }
2296
2297 // This function is used by two forms:
2298 // - renderEditLocationForm - all attributes may be modified
2299 // - renderRackspaceLocationEditor - only the name and parent may be modified
2300 function updateLocation ()
2301 {
2302 setFuncMessages (__FUNCTION__, array ('OK' => 6));
2303 global $pageno;
2304 $location_id = genericAssertion ('location_id', 'uint');
2305 $parent_id = genericAssertion ('parent_id', 'uint0');
2306 assertStringArg ('name');
2307
2308 if ($pageno == 'location')
2309 {
2310 $taglist = genericAssertion ('taglist', 'array0');
2311 $has_problems = isCheckSet ('has_problems', 'yesno');
2312 assertStringArg ('comment', TRUE);
2313 commitUpdateObject ($location_id, $_REQUEST['name'], NULL, $has_problems, NULL, $_REQUEST['comment']);
2314 updateObjectAttributes ($location_id);
2315 rebuildTagChainForEntity ('location', $location_id, buildTagChainFromIds ($taglist), TRUE);
2316 }
2317 else
2318 commitRenameObject ($location_id, $_REQUEST['name']);
2319
2320 $locationData = spotEntity ('location', $location_id);
2321
2322 // parent_id was submitted, but no link exists - create it
2323 if ($parent_id > 0 && !$locationData['parent_id'])
2324 commitLinkEntities ('location', $parent_id, 'location', $location_id);
2325
2326 // parent_id was submitted, but it doesn't match the existing link - update it
2327 if ($parent_id > 0 && $parent_id != $locationData['parent_id'])
2328 commitUpdateEntityLink
2329 (
2330 'location', $locationData['parent_id'], 'location', $location_id,
2331 'location', $parent_id, 'location', $location_id
2332 );
2333
2334 // no parent_id was submitted, but a link exists - delete it
2335 if ($parent_id == 0 && $locationData['parent_id'])
2336 commitUnlinkEntities ('location', $locationData['parent_id'], 'location', $location_id);
2337
2338 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
2339 }
2340
2341 function deleteLocation ()
2342 {
2343 setFuncMessages (__FUNCTION__, array ('OK' => 7, 'ERR1' => 206));
2344 $location_id = genericAssertion ('location_id', 'uint');
2345 $locationData = spotEntity ('location', $location_id);
2346 amplifyCell ($locationData);
2347 if (count ($locationData['locations']) || count ($locationData['rows']))
2348 {
2349 showFuncMessage (__FUNCTION__, 'ERR1', array ($locationData['name']));
2350 return;
2351 }
2352 releaseFiles ('location', $location_id);
2353 destroyTagsForEntity ('location', $location_id);
2354 commitDeleteObject ($location_id);
2355 showFuncMessage (__FUNCTION__, 'OK', array ($locationData['name']));
2356 return buildRedirectURL ('rackspace', 'editlocations');
2357 }
2358
2359 function addRow ()
2360 {
2361 setFuncMessages (__FUNCTION__, array ('OK' => 5));
2362 $location_id = genericAssertion ('location_id', 'uint0');
2363 assertStringArg ('name');
2364 $row_id = commitAddObject ($_REQUEST['name'], NULL, 1561, NULL);
2365 if ($location_id)
2366 commitLinkEntities ('location', $location_id, 'row', $row_id);
2367 showSuccess ('added row ' . mkA ($_REQUEST['name'], 'row', $row_id));
2368 }
2369
2370 // This function is used by two forms:
2371 // - renderEditRowForm - all attributes may be modified
2372 // - renderRackspaceRowEditor - only the name and location may be modified
2373 function updateRow ()
2374 {
2375 setFuncMessages (__FUNCTION__, array ('OK' => 6));
2376 $row_id = genericAssertion ('row_id', 'uint');
2377 $location_id = genericAssertion ('location_id', 'uint0');
2378 assertStringArg ('name');
2379
2380 commitUpdateObject ($row_id, $_REQUEST['name'], NULL, 'no', NULL, NULL);
2381
2382 global $pageno;
2383 if ($pageno == 'row')
2384 updateObjectAttributes ($row_id);
2385
2386 $rowData = spotEntity ('row', $row_id);
2387
2388 // location_id was submitted, but no link exists - create it
2389 if ($location_id > 0 && !$rowData['location_id'])
2390 commitLinkEntities ('location', $location_id, 'row', $row_id);
2391
2392 // location_id was submitted, but it doesn't match the existing link - update it
2393 if ($location_id > 0 && $location_id != $rowData['location_id'])
2394 commitUpdateEntityLink
2395 (
2396 'location', $rowData['location_id'], 'row', $row_id,
2397 'location', $location_id, 'row', $row_id
2398 );
2399
2400 // no parent_id was submitted, but a link exists - delete it
2401 if ($location_id == 0 && $rowData['location_id'])
2402 commitUnlinkEntities ('location', $rowData['location_id'], 'row', $row_id);
2403
2404 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
2405 }
2406
2407 function deleteRow ()
2408 {
2409 setFuncMessages (__FUNCTION__, array ('OK' => 7, 'UMOUNT' => 58));
2410 $row_id = assertUIntArg ('row_id');
2411 $rowData = spotEntity ('row', $row_id);
2412 $unmounted = getRowMountsCount ($row_id);
2413 commitDeleteRow ($row_id);
2414 if ($unmounted)
2415 showFuncMessage (__FUNCTION__, 'UMOUNT', array ($unmounted));
2416 showFuncMessage (__FUNCTION__, 'OK', array ($rowData['name']));
2417 return buildRedirectURL ('rackspace', 'editrows');
2418 }
2419
2420 function addRack ()
2421 {
2422 setFuncMessages (__FUNCTION__, array ('ERR2' => 172));
2423 $taglist = genericAssertion ('taglist', 'array0');
2424 $row_id = getBypassValue();
2425
2426 // The new rack(s) should be placed on the bottom of the list, sort-wise
2427 $rowInfo = getRowInfo ($row_id);
2428 $sort_order = $rowInfo['count']+1;
2429
2430 switch (genericAssertion ('mode', 'string'))
2431 {
2432 case 'one':
2433 assertStringArg ('name');
2434 $height = genericAssertion ('height1', 'uint');
2435 assertStringArg ('asset_no', TRUE);
2436 $rack_id = commitAddObject ($_REQUEST['name'], NULL, 1560, $_REQUEST['asset_no'], $taglist);
2437
2438 // Set the height and sort order
2439 commitUpdateAttrValue ($rack_id, 27, $height);
2440 commitUpdateAttrValue ($rack_id, 29, $sort_order);
2441
2442 // Link it to the row
2443 commitLinkEntities ('row', $row_id, 'rack', $rack_id);
2444 showSuccess ('added ' . mkCellA (spotEntity ('rack', $rack_id)));
2445 break;
2446 case 'many':
2447 $height = genericAssertion ('height2', 'uint');
2448 assertStringArg ('names', TRUE);
2449 foreach (textareaCooked ($_REQUEST['names']) as $cname)
2450 {
2451 $rack_id = commitAddObject ($cname, NULL, 1560, NULL, $taglist);
2452
2453 // Set the height and sort order
2454 commitUpdateAttrValue ($rack_id, 27, $height);
2455 commitUpdateAttrValue ($rack_id, 29, $sort_order);
2456 $sort_order++;
2457
2458 // Link it to the row
2459 commitLinkEntities ('row', $row_id, 'rack', $rack_id);
2460 showSuccess ('added ' . mkCellA (spotEntity ('rack', $rack_id)));
2461 }
2462 break;
2463 default:
2464 showFuncMessage (__FUNCTION__, 'ERR2');
2465 }
2466 }
2467
2468 function updateRack ()
2469 {
2470 setFuncMessages (__FUNCTION__, array ('OK' => 6));
2471 $row_id = genericAssertion ('row_id', 'uint');
2472 assertStringArg ('name');
2473 $height = genericAssertion ('height', 'uint');
2474 assertStringArg ('asset_no', TRUE);
2475 assertStringArg ('comment', TRUE);
2476 $taglist = genericAssertion ('taglist', 'array0');
2477 $rack_id = getBypassValue();
2478 usePreparedDeleteBlade ('RackThumbnail', array ('rack_id' => $rack_id));
2479 commitUpdateRack
2480 (
2481 $rack_id,
2482 $row_id,
2483 $_REQUEST['name'],
2484 $height,
2485 isCheckSet ('has_problems', 'yesno'),
2486 $_REQUEST['asset_no'],
2487 $_REQUEST['comment']
2488 );
2489 updateObjectAttributes ($rack_id);
2490 rebuildTagChainForEntity ('rack', $rack_id, buildTagChainFromIds ($taglist), TRUE);
2491 showFuncMessage (__FUNCTION__, 'OK', array ($_REQUEST['name']));
2492 }
2493
2494 function deleteRack ()
2495 {
2496 setFuncMessages (__FUNCTION__, array ('OK' => 7, 'ERR1' => 206));
2497 $rackData = spotEntity ('rack', getBypassValue());
2498 amplifyCell ($rackData);
2499 if (!$rackData['isDeletable'])
2500 {
2501 showFuncMessage (__FUNCTION__, 'ERR1');
2502 return;
2503 }
2504 commitDeleteRack ($rackData['id']);
2505 showFuncMessage (__FUNCTION__, 'OK', array (formatEntityName ($rackData)));
2506 return buildRedirectURL ('rackspace', 'default');
2507 }
2508
2509 function cleanRack ()
2510 {
2511 setFuncMessages (__FUNCTION__, array ('OK' => 58));
2512 $rack_id = getBypassValue();
2513 $unmounted = getRackMountsCount ($rack_id);
2514 commitCleanRack ($rack_id);
2515 showFuncMessage (__FUNCTION__, 'OK', array ($unmounted));
2516 }
2517
2518 function updateRackDesign ()
2519 {
2520 $rackData = spotEntity ('rack', getBypassValue());
2521 amplifyCell ($rackData);
2522 applyRackDesignMask($rackData);
2523 if (processGridForm ($rackData, 'A', 'F'))
2524 showSuccess ("Saved successfully");
2525 else
2526 showNotice ("Nothing saved");
2527 }
2528
2529 function updateRackProblems ()
2530 {
2531 $rackData = spotEntity ('rack', getBypassValue());
2532 amplifyCell ($rackData);
2533 applyRackProblemMask($rackData);
2534 if (processGridForm ($rackData, 'F', 'U'))
2535 showSuccess ("Saved successfully");
2536 else
2537 showNotice ("Nothing saved");
2538 }
2539
2540 function querySNMPData ()
2541 {
2542 $ver = genericAssertion ('ver', 'uint');
2543 $snmpsetup = array ();
2544 switch ($ver)
2545 {
2546 case 1:
2547 case 2:
2548 genericAssertion ('community', 'string');
2549 $snmpsetup['community'] = $_REQUEST['community'];
2550 break;
2551 case 3:
2552 assertStringArg ('sec_name');
2553 assertStringArg ('sec_level');
2554 assertStringArg ('auth_protocol');
2555 assertStringArg ('auth_passphrase', TRUE);
2556 assertStringArg ('priv_protocol');
2557 assertStringArg ('priv_passphrase', TRUE);
2558
2559 $snmpsetup['sec_name'] = $_REQUEST['sec_name'];
2560 $snmpsetup['sec_level'] = $_REQUEST['sec_level'];
2561 $snmpsetup['auth_protocol'] = $_REQUEST['auth_protocol'];
2562 $snmpsetup['auth_passphrase'] = $_REQUEST['auth_passphrase'];
2563 $snmpsetup['priv_protocol'] = $_REQUEST['priv_protocol'];
2564 $snmpsetup['priv_passphrase'] = $_REQUEST['priv_passphrase'];
2565 break;
2566 default:
2567 throw new InvalidRequestArgException ('ver', $ver);
2568 }
2569 $snmpsetup['version'] = $ver;
2570 doSNMPmining (getBypassValue(), $snmpsetup); // shows message by itself
2571 }
2572
2573 // File-related functions
2574 function addFileWithoutLink ()
2575 {
2576 setFuncMessages (__FUNCTION__, array ('OK' => 5, 'ERR1' => 207));
2577 assertStringArg ('comment', TRUE);
2578
2579 // Make sure the file can be uploaded
2580 if (get_cfg_var('file_uploads') != 1)
2581 throw new RackTablesError ('file uploads not allowed, change "file_uploads" parameter in php.ini', RackTablesError::MISCONFIGURED);
2582
2583 // Exit if the upload failed
2584 if ($_FILES['file']['error'])
2585 {
2586 showFuncMessage (__FUNCTION__, 'ERR1', array ($_FILES['file']['error']));
2587 return;
2588 }
2589 if (FALSE === $fp = fopen($_FILES['file']['tmp_name'], 'rb'))
2590 {
2591 showFuncMessage (__FUNCTION__, 'ERR1', array ('failed to access the temporary file'));
2592 return;
2593 }
2594
2595 $file_id = commitAddFile ($_FILES['file']['name'], $_FILES['file']['type'], $fp, genericAssertion ('comment', 'string0'));
2596 if (isset ($_REQUEST['taglist']))
2597 produceTagsForNewRecord ('file', $_REQUEST['taglist'], $file_id);
2598 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($_FILES['file']['name'])));
2599 }
2600
2601 function addFileToEntity ()
2602 {
2603 setFuncMessages (__FUNCTION__, array ('OK' => 5, 'ERR1' => 207));
2604 $realm = etypeByPageno();
2605 assertStringArg ('comment', TRUE);
2606
2607 // Make sure the file can be uploaded
2608 if (get_cfg_var('file_uploads') != 1)
2609 throw new RackTablesError ('file uploads not allowed, change "file_uploads" parameter in php.ini', RackTablesError::MISCONFIGURED);
2610
2611 // Exit if the upload failed
2612 if ($_FILES['file']['error'])
2613 {
2614 showFuncMessage (__FUNCTION__, 'ERR1', array ($_FILES['file']['error']));
2615 return;
2616 }
2617 if (FALSE === $fp = fopen($_FILES['file']['tmp_name'], 'rb'))
2618 {
2619 showFuncMessage (__FUNCTION__, 'ERR1', array ('failed to access the temporary file'));
2620 return;
2621 }
2622
2623 commitAddFile ($_FILES['file']['name'], $_FILES['file']['type'], $fp, genericAssertion ('comment', 'string0'));
2624 usePreparedInsertBlade
2625 (
2626 'FileLink',
2627 array
2628 (
2629 'file_id' => lastInsertID(),
2630 'entity_type' => $realm,
2631 'entity_id' => getBypassValue(),
2632 )
2633 );
2634 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($_FILES['file']['name'])));
2635 }
2636
2637 function linkFileToEntity ()
2638 {
2639 setFuncMessages (__FUNCTION__, array ('OK' => 71));
2640 $fi = spotEntity ('file', genericAssertion ('file_id', 'uint'));
2641 usePreparedInsertBlade
2642 (
2643 'FileLink',
2644 array
2645 (
2646 'file_id' => $fi['id'],
2647 'entity_type' => etypeByPageno(),
2648 'entity_id' => getBypassValue(),
2649 )
2650 );
2651 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($fi['name'])));
2652 }
2653
2654 function replaceFile ()
2655 {
2656 setFuncMessages (__FUNCTION__, array ('OK' => 6, 'ERR2' => 201));
2657 // Make sure the file can be uploaded
2658 if (get_cfg_var('file_uploads') != 1)
2659 throw new RackTablesError ('file uploads not allowed, change "file_uploads" parameter in php.ini', RackTablesError::MISCONFIGURED);
2660 $shortInfo = spotEntity ('file', getBypassValue());
2661
2662 if (FALSE === $fp = fopen ($_FILES['file']['tmp_name'], 'rb'))
2663 {
2664 showFuncMessage (__FUNCTION__, 'ERR2');
2665 return;
2666 }
2667 commitReplaceFile ($shortInfo['id'], $fp);
2668
2669 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($shortInfo['name'])));
2670 }
2671
2672 function unlinkFile ()
2673 {
2674 setFuncMessages (__FUNCTION__, array ('OK' => 72));
2675 commitUnlinkFile (genericAssertion ('link_id', 'uint'));
2676 showFuncMessage (__FUNCTION__, 'OK');
2677 }
2678
2679 function deleteFile ()
2680 {
2681 setFuncMessages (__FUNCTION__, array ('OK' => 7));
2682 $file_id = genericAssertion ('file_id', 'uint');
2683 $shortInfo = spotEntity ('file', $file_id);
2684 commitDeleteFile ($file_id);
2685 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($shortInfo['name'])));
2686 }
2687
2688 function updateFileText ()
2689 {
2690 setFuncMessages (__FUNCTION__, array ('OK' => 6, 'ERR1' => 179, 'ERR2' => 155));
2691 $shortInfo = spotEntity ('file', getBypassValue());
2692 if ($shortInfo['mtime'] != genericAssertion ('mtime_copy', 'string'))
2693 {
2694 showFuncMessage (__FUNCTION__, 'ERR1');
2695 return;
2696 }
2697 commitReplaceFile ($shortInfo['id'], genericAssertion ('file_text', 'string0'));
2698 showFuncMessage (__FUNCTION__, 'OK', array (htmlspecialchars ($shortInfo['name'])));
2699 }
2700
2701 function addIIFOIFCompatPack ()
2702 {
2703 setFuncMessages (__FUNCTION__, array ('OK' => 37));
2704 $standard = genericAssertion ('standard', 'enum/wdmstd');
2705 $iif_id = genericAssertion ('iif_id', 'iif');
2706 global $wdm_packs;
2707 $ngood = 0;
2708 foreach ($wdm_packs[$standard]['oif_ids'] as $oif_id)
2709 {
2710 commitSupplementPIC ($iif_id, $oif_id);
2711 $ngood++;
2712 }
2713 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
2714 }
2715
2716 function addOIFCompat ()
2717 {
2718 $type1 = assertUIntArg ('type1');
2719 $type2 = assertUIntArg ('type2');
2720 $n_changed = addPortOIFCompat ($type1, $type2);
2721 showSuccess ("$n_changed row(s) added");
2722 }
2723
2724 function delOIFCompat ()
2725 {
2726 $type1 = assertUIntArg ('type1');
2727 $type2 = assertUIntArg ('type2');
2728 $n_changed = deletePortOIFCompat ($type1, $type2);
2729 showSuccess ("$n_changed row(s) deleted");
2730 }
2731
2732 function delIIFOIFCompatPack ()
2733 {
2734 setFuncMessages (__FUNCTION__, array ('OK' => 38));
2735 $standard = genericAssertion ('standard', 'enum/wdmstd');
2736 $iif_id = genericAssertion ('iif_id', 'iif');
2737 global $wdm_packs;
2738 $ngood = 0;
2739 foreach ($wdm_packs[$standard]['oif_ids'] as $oif_id)
2740 {
2741 usePreparedDeleteBlade ('PortInterfaceCompat', array ('iif_id' => $iif_id, 'oif_id' => $oif_id));
2742 $ngood++;
2743 }
2744 showFuncMessage (__FUNCTION__, 'OK', array ($ngood));
2745 }
2746
2747 function addOIFCompatPack ()
2748 {
2749 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2750 global $wdm_packs;
2751 $oifs = $wdm_packs[genericAssertion ('standard', 'enum/wdmstd')]['oif_ids'];
2752 foreach ($oifs as $oif_id_1)
2753 {
2754 $args = $qmarks = array();
2755 $query = 'REPLACE INTO PortCompat (type1, type2) VALUES ';
2756 foreach ($oifs as $oif_id_2)
2757 {
2758 $qmarks[] = '(?, ?)';
2759 $args[] = $oif_id_1;
2760 $args[] = $oif_id_2;
2761 }
2762 $query .= implode (', ', $qmarks);
2763 usePreparedExecuteBlade ($query, $args);
2764 }
2765 showFuncMessage (__FUNCTION__, 'OK');
2766 }
2767
2768 function delOIFCompatPack ()
2769 {
2770 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2771 global $wdm_packs;
2772 $oifs = $wdm_packs[genericAssertion ('standard', 'enum/wdmstd')]['oif_ids'];
2773 foreach ($oifs as $oif_id_1)
2774 foreach ($oifs as $oif_id_2)
2775 if ($oif_id_1 != $oif_id_2) # leave narrow-band mapping intact
2776 usePreparedDeleteBlade ('PortCompat', array ('type1' => $oif_id_1, 'type2' => $oif_id_2));
2777 showFuncMessage (__FUNCTION__, 'OK');
2778 }
2779
2780 function add8021QOrder ()
2781 {
2782 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2783 $vdom_id = genericAssertion ('vdom_id', 'uint');
2784 $object_id = genericAssertion ('object_id', 'uint');
2785 $vst_id = genericAssertion ('vst_id', 'uint');
2786 global $pageno;
2787 fixContext();
2788 if ($pageno != 'object')
2789 spreadContext (spotEntity ('object', $object_id));
2790 if ($pageno != 'vst')
2791 spreadContext (spotEntity ('vst', $vst_id));
2792 assertPermission();
2793 usePreparedExecuteBlade
2794 (
2795 'INSERT INTO VLANSwitch (domain_id, object_id, template_id, last_change, out_of_sync) ' .
2796 'VALUES (?, ?, ?, NOW(), "yes")',
2797 array ($vdom_id, $object_id, $vst_id)
2798 );
2799 showFuncMessage (__FUNCTION__, 'OK');
2800 }
2801
2802 function del8021QOrder ()
2803 {
2804 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2805 $object_id = genericAssertion ('object_id', 'uint');
2806 $vdom_id = genericAssertion ('vdom_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 usePreparedDeleteBlade ('VLANSwitch', array ('object_id' => $object_id));
2816 $focus_hints = array
2817 (
2818 'prev_objid' => $object_id,
2819 'prev_vstid' => $vst_id,
2820 'prev_vdid' => $vdom_id,
2821 );
2822 showFuncMessage (__FUNCTION__, 'OK');
2823 return buildRedirectURL (NULL, NULL, $focus_hints);
2824 }
2825
2826 function createVLANDomain ()
2827 {
2828 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2829 usePreparedInsertBlade
2830 (
2831 'VLANDomain',
2832 array
2833 (
2834 'description' => genericAssertion ('vdom_descr', 'string'),
2835 )
2836 );
2837 $domain_id = lastInsertID();
2838 lastCreated ('vdom', $domain_id);
2839 usePreparedInsertBlade
2840 (
2841 'VLANDescription',
2842 array
2843 (
2844 'domain_id' => $domain_id,
2845 'vlan_id' => VLAN_DFL_ID,
2846 'vlan_type' => 'compulsory',
2847 'vlan_descr' => 'default',
2848 )
2849 );
2850 showFuncMessage (__FUNCTION__, 'OK');
2851 }
2852
2853 function save8021QPorts ()
2854 {
2855 setFuncMessages (__FUNCTION__, array ('OK' => 21));
2856 global $sic;
2857 $object_id = getBypassValue();
2858 $form_mode = genericAssertion ('form_mode', 'string');
2859 if ($form_mode != 'save' && $form_mode != 'duplicate')
2860 throw new InvalidRequestArgException ('form_mode', $form_mode);
2861 $extra = array();
2862
2863 // prepare the $changes array
2864 $changes = array();
2865 switch ($form_mode)
2866 {
2867 case 'save':
2868 $nports = genericAssertion ('nports', 'uint');
2869 if ($nports == 1)
2870 $extra = array ('port_name' => genericAssertion ('pn_0', 'string'));
2871 for ($i = 0; $i < $nports; $i++)
2872 {
2873 $portname = assertStringArg ('pn_' . $i);
2874 $portmode = assertStringArg ('pm_' . $i);
2875 // An access port only generates form input for its native VLAN,
2876 // which we derive allowed VLAN list from.
2877 $native = isset ($sic['pnv_' . $i]) ? $sic['pnv_' . $i] : 0;
2878 switch ($portmode)
2879 {
2880 case 'trunk':
2881 # assertArrayArg ('pav_' . $i);
2882 $allowed = isset ($sic['pav_' . $i]) ? $sic['pav_' . $i] : array();
2883 break;
2884 case 'access':
2885 if ($native == 'same')
2886 continue 2;
2887 assertUIntArg ('pnv_' . $i);
2888 $allowed = array ($native);
2889 break;
2890 default:
2891 throw new InvalidRequestArgException ("pm_${i}", $portmode, 'unknown port mode');
2892 }
2893 $changes[$portname] = array
2894 (
2895 'mode' => $portmode,
2896 'allowed' => $allowed,
2897 'native' => $native,
2898 );
2899 }
2900 break;
2901 case 'duplicate':
2902 $from_port = genericAssertion ('from_port', 'string');
2903 $before = getStored8021QConfig ($object_id, 'desired');
2904 if (!array_key_exists ($from_port, $before))
2905 throw new InvalidArgException ('from_port', $from_port, 'this port does not exist');
2906 foreach (genericAssertion ('to_ports', 'array0') as $tpn)
2907 if (!array_key_exists ($tpn, $before))
2908 throw new InvalidArgException ('to_ports[]', $tpn, 'this port does not exist');
2909 elseif ($tpn != $from_port)
2910 $changes[$tpn] = $before[$from_port];
2911 break;
2912 }
2913 apply8021qChangeRequest ($object_id, $changes, TRUE, genericAssertion ('mutex_rev', 'uint0'));
2914 return buildRedirectURL (NULL, NULL, $extra);
2915 }
2916
2917 function bindVLANtoIPv4 ()
2918 {
2919 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2920 commitSupplementVLANIPv4 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2921 showFuncMessage (__FUNCTION__, 'OK');
2922 }
2923
2924 function bindVLANtoIPv6 ()
2925 {
2926 setFuncMessages (__FUNCTION__, array ('OK' => 48));
2927 commitSupplementVLANIPv6 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2928 showFuncMessage (__FUNCTION__, 'OK');
2929 }
2930
2931 function unbindVLANfromIPv4 ()
2932 {
2933 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2934 commitReduceVLANIPv4 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2935 showFuncMessage (__FUNCTION__, 'OK');
2936 }
2937
2938 function unbindVLANfromIPv6 ()
2939 {
2940 setFuncMessages (__FUNCTION__, array ('OK' => 49));
2941 commitReduceVLANIPv6 (genericAssertion ('vlan_ck', 'uint-vlan1'), genericAssertion ('id', 'uint'));
2942 showFuncMessage (__FUNCTION__, 'OK');
2943 }
2944
2945 function process8021QSyncRequest ()
2946 {
2947 setFuncMessages (__FUNCTION__, array ('OK' => 63, 'ERR' => 191));
2948 // behave depending on current operation: exec8021QPull or exec8021QPush
2949 global $op;
2950 if (FALSE === $done = exec8021QDeploy (getBypassValue(), $op == 'exec8021QPush'))
2951 showFuncMessage (__FUNCTION__, 'ERR');
2952 else
2953 showFuncMessage (__FUNCTION__, 'OK', array ($done));
2954 }
2955
2956 function process8021QRecalcRequest ()
2957 {
2958 setFuncMessages (__FUNCTION__, array ('OK' => 87));
2959 assertPermission (NULL, NULL, NULL, array (array ('tag' => '$op_recalc8021Q')));
2960 $counters = recalc8021QPorts (getBypassValue());
2961 if ($counters['ports'])
2962 showFuncMessage (__FUNCTION__, 'OK', array ($counters['ports'], $counters['switches']));
2963 else
2964 showNotice ('No changes were made');
2965 }
2966
2967 function resolve8021QConflicts ()
2968 {
2969 setFuncMessages (__FUNCTION__, array ('OK' => 63, 'ERR1' => 179, 'ERR2' => 109));
2970 global $sic, $dbxlink;
2971 $mutex_rev = genericAssertion ('mutex_rev', 'uint0'); // counts from 0
2972 $nrows = genericAssertion ('nrows', 'uint');
2973 $object_id = getBypassValue();
2974 // Divide submitted radio buttons into 3 groups:
2975 // left (saved version wins)
2976 // asis (ignore)
2977 // right (running version wins)
2978 $F = array();
2979 for ($i = 0; $i < $nrows; $i++)
2980 {
2981 if (!array_key_exists ("i_${i}", $sic))
2982 continue;
2983 // let's hope other inputs are in place
2984 switch ($sic["i_${i}"])
2985 {
2986 case 'left':
2987 case 'right':
2988 $F[$sic["pn_${i}"]] = array
2989 (
2990 'mode' => $sic["rm_${i}"],
2991 'allowed' => array_fetch ($sic, "ra_${i}", array()),
2992 'native' => $sic["rn_${i}"],
2993 'decision' => $sic["i_${i}"],
2994 );
2995 break;
2996 default:
2997 // don't care
2998 }
2999 }
3000 $dbxlink->beginTransaction();
3001 try
3002 {
3003 if (NULL === $vswitch = getVLANSwitchInfo ($object_id, 'FOR UPDATE'))
3004 throw new InvalidArgException ('object_id', $object_id, 'VLAN domain is not set for this object');
3005 if ($vswitch['mutex_rev'] != $mutex_rev)
3006 throw new InvalidRequestArgException ('mutex_rev', $mutex_rev, 'expired form (table data has changed)');
3007 $D = getStored8021QConfig ($vswitch['object_id'], 'desired');
3008 $C = getStored8021QConfig ($vswitch['object_id'], 'cached');
3009 $R = getRunning8021QConfig ($vswitch['object_id']);
3010 $plan = get8021QSyncOptions ($vswitch, $D, $C, $R['portdata']);
3011 $ndone = 0;
3012 foreach ($F as $port_name => $port)
3013 {
3014 if (!array_key_exists ($port_name, $plan))
3015 continue;
3016 elseif ($plan[$port_name]['status'] == 'merge_conflict')
3017 {
3018 // for R neither mutex nor revisions can be emulated, but revision change can be
3019 if (!same8021QConfigs ($port, $R['portdata'][$port_name]))
3020 throw new InvalidRequestArgException ("port ${port_name}", '(hidden)', 'expired form (switch data has changed)');
3021 if ($port['decision'] == 'right') // D wins, frame R by writing value of R to C
3022 $ndone += upd8021QPort ('cached', $vswitch['object_id'], $port_name, $port, $C[$port_name]);
3023 elseif ($port['decision'] == 'left') // R wins, cross D up
3024 $ndone += upd8021QPort ('cached', $vswitch['object_id'], $port_name, $D[$port_name], $C[$port_name]);
3025 // otherwise there was no decision made
3026 }
3027 elseif
3028 (
3029 $plan[$port_name]['status'] == 'delete_conflict' or
3030 $plan[$port_name]['status'] == 'martian_conflict'
3031 )
3032 if ($port['decision'] == 'left')
3033 // confirm deletion of local copy
3034 $ndone += del8021QPort ($vswitch['object_id'], $port_name);
3035 // otherwise ignore a decision that doesn't address a conflict
3036 }
3037 }
3038 catch (InvalidRequestArgException $e)
3039 {
3040 $dbxlink->rollBack();
3041 showFuncMessage (__FUNCTION__, 'ERR1');
3042 return;
3043 }
3044 catch (Exception $e)
3045 {
3046 $dbxlink->rollBack();
3047 showFuncMessage (__FUNCTION__, 'ERR2');
3048 return;
3049 }
3050 $dbxlink->commit();
3051 showFuncMessage (__FUNCTION__, 'OK', array ($ndone));
3052 }
3053
3054 function update8021QPortList()
3055 {
3056 genericAssertion ('ports', 'array');
3057 $enabled = $disabled = 0;
3058 $default_port = array
3059 (
3060 'mode' => 'access',
3061 'allowed' => array (VLAN_DFL_ID),
3062 'native' => VLAN_DFL_ID,
3063 );
3064 foreach (genericAssertion ('ports', 'array') as $line)
3065 if (preg_match ('/^enable (.+)$/', $line, $m))
3066 $enabled += add8021QPort (getBypassValue(), $m[1], $default_port);
3067 elseif (preg_match ('/^disable (.+)$/', $line, $m))
3068 $disabled += del8021QPort (getBypassValue(), $m[1]);
3069 else
3070 throw new InvalidRequestArgException ('ports[]', $line, 'malformed array item');
3071 # $enabled + $disabled > 0
3072 if ($enabled)
3073 showSuccess ("enabled 802.1Q for ${enabled} port(s)");
3074 if ($disabled)
3075 showSuccess ("disabled 802.1Q for ${disabled} port(s)");
3076 }
3077
3078 function cloneVST()
3079 {
3080 setFuncMessages (__FUNCTION__, array ('OK' => 48));
3081 $src_vst = spotEntity ('vst', genericAssertion ('from_id', 'uint'));
3082 amplifyCell ($src_vst);
3083 commitUpdateVSTRules (getBypassValue(), genericAssertion ('mutex_rev', 'uint0'), $src_vst['rules']);
3084 showFuncMessage (__FUNCTION__, 'OK');
3085 }
3086
3087 function updVSTRule()
3088 {
3089 setFuncMessages (__FUNCTION__, array ('OK' => 43));
3090 // this is used for making throwing an invalid argument exception easier.
3091 function updVSTRule_get_named_param ($name, $haystack, &$last_used_name)
3092 {
3093 $last_used_name = $name;
3094 return isset ($haystack[$name]) ? $haystack[$name] : NULL;
3095 }
3096
3097 global $port_role_options;
3098 $vst_id = getBypassValue();
3099 $taglist = genericAssertion ('taglist', 'array0');
3100 $mutex_rev = genericAssertion ('mutex_rev', 'uint0');
3101 $data = genericAssertion ('template_json', 'json');
3102 $rule_no = 0;
3103 try
3104 {
3105 $last_field = '';
3106 foreach ($data as $rule)
3107 {
3108 $rule_no++;
3109 if
3110 (
3111 ! isInteger (updVSTRule_get_named_param ('rule_no', $rule, $last_field)) ||
3112 ! isPCRE (updVSTRule_get_named_param ('port_pcre', $rule, $last_field)) ||
3113 NULL === updVSTRule_get_named_param ('port_role', $rule, $last_field) ||
3114 ! array_key_exists (updVSTRule_get_named_param ('port_role', $rule, $last_field), $port_role_options) ||
3115 NULL === updVSTRule_get_named_param ('wrt_vlans', $rule, $last_field) ||
3116 ! preg_match ('/^[ 0-9\-,]*$/', updVSTRule_get_named_param ('wrt_vlans', $rule, $last_field)) ||
3117 NULL === updVSTRule_get_named_param ('description', $rule, $last_field)
3118 )
3119 throw new InvalidRequestArgException ($last_field, $rule[$last_field], "rule #$rule_no");
3120 }
3121 commitUpdateVSTRules ($vst_id, $mutex_rev, $data);
3122 }
3123 catch (Exception $e)
3124 {
3125 // Every case that is soft-processed in process.php, will have the working copy available for a retry.
3126 if ($e instanceof InvalidRequestArgException || $e instanceof RTDatabaseError)
3127 {
3128 startSession();
3129 $_SESSION['vst_edited'] = $data;
3130 session_commit();
3131 }
3132 throw $e;
3133 }
3134 rebuildTagChainForEntity ('vst', $vst_id, buildTagChainFromIds ($taglist),