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