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