1<?php 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22/** 23 * Import formatter 24 */ 25class CImportDataAdapter { 26 27 /** 28 * @var array configuration import data 29 */ 30 protected $data; 31 32 /** 33 * Current import version. 34 * 35 * @var string 36 */ 37 protected $currentVersion; 38 39 /** 40 * Set the data and initialize the adapter. 41 * 42 * @param array $data import data 43 */ 44 public function load(array $data) { 45 $this->data = $data['zabbix_export']; 46 } 47 48 /** 49 * Get groups from the imported data. 50 * 51 * @return array 52 */ 53 public function getGroups() { 54 return array_key_exists('groups', $this->data) ? $this->data['groups'] : []; 55 } 56 57 /** 58 * Get templates from the imported data. 59 * 60 * @return array 61 */ 62 public function getTemplates() { 63 $templates = []; 64 65 if (array_key_exists('templates', $this->data)) { 66 foreach ($this->data['templates'] as $template) { 67 $template = CArrayHelper::renameKeys($template, ['template' => 'host']); 68 69 $templates[] = CArrayHelper::getByKeys($template, [ 70 'groups', 'macros', 'templates', 'host', 'status', 'name', 'description', 'tags' 71 ]); 72 } 73 } 74 75 return $templates; 76 } 77 78 /** 79 * Get hosts from the imported data. 80 * 81 * @return array 82 */ 83 public function getHosts() { 84 $hosts = []; 85 86 if (array_key_exists('hosts', $this->data)) { 87 foreach ($this->data['hosts'] as $host) { 88 $host = CArrayHelper::renameKeys($host, ['proxyid' => 'proxy_hostid']); 89 90 if (array_key_exists('interfaces', $host)) { 91 foreach ($host['interfaces'] as $inum => $interface) { 92 $host['interfaces'][$inum] = CArrayHelper::renameKeys($interface, ['default' => 'main']); 93 } 94 } 95 96 $hosts[] = CArrayHelper::getByKeys($host, [ 97 'inventory', 'proxy', 'groups', 'templates', 'macros', 'interfaces', 'host', 'status', 98 'description', 'ipmi_authtype', 'ipmi_privilege', 'ipmi_username', 'ipmi_password', 'name', 99 'inventory_mode', 'tls_connect', 'tls_accept', 'tls_issuer', 'tls_subject', 'tls_psk_identity', 100 'tls_psk', 'tags' 101 ]); 102 } 103 } 104 105 return $hosts; 106 } 107 108 /** 109 * Get applications from the imported data. 110 * 111 * @return array 112 */ 113 public function getApplications() { 114 $applications = []; 115 116 if (array_key_exists('hosts', $this->data)) { 117 foreach ($this->data['hosts'] as $host) { 118 if (array_key_exists('applications', $host)) { 119 foreach ($host['applications'] as $application) { 120 $applications[$host['host']][$application['name']] = $application; 121 } 122 } 123 } 124 } 125 126 if (array_key_exists('templates', $this->data)) { 127 foreach ($this->data['templates'] as $template) { 128 if (array_key_exists('applications', $template)) { 129 foreach ($template['applications'] as $application) { 130 $applications[$template['template']][$application['name']] = $application; 131 } 132 } 133 } 134 } 135 136 return $applications; 137 } 138 139 /** 140 * Get value maps from the imported data. 141 * 142 * @return array 143 */ 144 public function getValueMaps() { 145 return array_key_exists('value_maps', $this->data) ? $this->data['value_maps'] : []; 146 } 147 148 /** 149 * Get items from the imported data. 150 * 151 * @return array 152 */ 153 public function getItems() { 154 $items = []; 155 156 if (array_key_exists('hosts', $this->data)) { 157 foreach ($this->data['hosts'] as $host) { 158 if (array_key_exists('items', $host)) { 159 foreach ($host['items'] as $item) { 160 $items[$host['host']][$item['key']] = $this->renameItemFields($item); 161 } 162 } 163 } 164 } 165 166 if (array_key_exists('templates', $this->data)) { 167 foreach ($this->data['templates'] as $template) { 168 if (array_key_exists('items', $template)) { 169 foreach ($template['items'] as $item) { 170 $items[$template['template']][$item['key']] = $this->renameItemFields($item); 171 } 172 } 173 } 174 } 175 176 return $items; 177 } 178 179 /** 180 * Get discovery rules from the imported data. 181 * 182 * @return array 183 */ 184 public function getDiscoveryRules() { 185 $discovery_rules = []; 186 187 if (array_key_exists('hosts', $this->data)) { 188 foreach ($this->data['hosts'] as $host) { 189 if (array_key_exists('discovery_rules', $host)) { 190 foreach ($host['discovery_rules'] as $discovery_rule) { 191 $discovery_rules[$host['host']][$discovery_rule['key']] = 192 $this->formatDiscoveryRule($discovery_rule, $host['host']); 193 } 194 } 195 } 196 } 197 198 if (array_key_exists('templates', $this->data)) { 199 foreach ($this->data['templates'] as $template) { 200 if (array_key_exists('discovery_rules', $template)) { 201 foreach ($template['discovery_rules'] as $discovery_rule) { 202 $discovery_rules[$template['template']][$discovery_rule['key']] = 203 $this->formatDiscoveryRule($discovery_rule, $template['template']); 204 } 205 } 206 } 207 } 208 209 return $discovery_rules; 210 } 211 212 /** 213 * Get web scenarios from the imported data. 214 * 215 * @return array 216 */ 217 public function getHttpTests() { 218 $httptests = []; 219 220 if (array_key_exists('hosts', $this->data)) { 221 foreach ($this->data['hosts'] as $host) { 222 if (array_key_exists('httptests', $host)) { 223 foreach ($host['httptests'] as $httptest) { 224 $httptests[$host['host']][$httptest['name']] = $this->formatHttpTest($httptest); 225 } 226 } 227 } 228 } 229 230 if (array_key_exists('templates', $this->data)) { 231 foreach ($this->data['templates'] as $template) { 232 if (array_key_exists('httptests', $template)) { 233 foreach ($template['httptests'] as $httptest) { 234 $httptests[$template['template']][$httptest['name']] = $this->formatHttpTest($httptest); 235 } 236 } 237 } 238 } 239 240 return $httptests; 241 } 242 243 /** 244 * Get web scenario steps from the imported data. 245 * 246 * @return array 247 */ 248 public function getHttpSteps() { 249 $httpsteps = []; 250 251 if (array_key_exists('hosts', $this->data)) { 252 foreach ($this->data['hosts'] as $host) { 253 if (array_key_exists('httptests', $host)) { 254 foreach ($host['httptests'] as $httptest) { 255 foreach ($httptest['steps'] as $httpstep) { 256 $httpsteps[$host['host']][$httptest['name']][$httpstep['name']] = $httpstep; 257 } 258 } 259 } 260 } 261 } 262 263 if (array_key_exists('templates', $this->data)) { 264 foreach ($this->data['templates'] as $template) { 265 if (array_key_exists('httptests', $template)) { 266 foreach ($template['httptests'] as $httptest) { 267 foreach ($httptest['steps'] as $httpstep) { 268 $httpsteps[$template['template']][$httptest['name']][$httpstep['name']] = $httpstep; 269 } 270 } 271 } 272 } 273 } 274 275 return $httpsteps; 276 } 277 278 /** 279 * Get graphs from the imported data. 280 * 281 * @return array 282 */ 283 public function getGraphs() { 284 $graphs = []; 285 286 if (array_key_exists('graphs', $this->data)) { 287 foreach ($this->data['graphs'] as $graph) { 288 $graphs[] = $this->renameGraphFields($graph); 289 } 290 } 291 292 return $graphs; 293 } 294 295 /** 296 * Get simple triggers from the imported data. 297 * 298 * @return array 299 */ 300 protected function getSimpleTriggers() { 301 $simple_triggers = []; 302 $expression_options = ['lldmacros' => false, 'allow_func_only' => true]; 303 304 if (array_key_exists('hosts', $this->data)) { 305 foreach ($this->data['hosts'] as $host) { 306 if (array_key_exists('items', $host)) { 307 foreach ($host['items'] as $item) { 308 if (array_key_exists('triggers', $item)) { 309 foreach ($item['triggers'] as $simple_trigger) { 310 $simple_trigger = $this->enrichSimpleTriggerExpression($host['host'], $item['key'], 311 $simple_trigger, $expression_options 312 ); 313 $simple_triggers[] = $this->renameTriggerFields($simple_trigger); 314 } 315 unset($item['triggers']); 316 } 317 } 318 } 319 } 320 } 321 322 if (array_key_exists('templates', $this->data)) { 323 foreach ($this->data['templates'] as $template) { 324 if (array_key_exists('items', $template)) { 325 foreach ($template['items'] as $item) { 326 if (array_key_exists('triggers', $item)) { 327 foreach ($item['triggers'] as $simple_trigger) { 328 $simple_trigger = $this->enrichSimpleTriggerExpression($template['template'], 329 $item['key'], $simple_trigger, $expression_options 330 ); 331 $simple_triggers[] = $this->renameTriggerFields($simple_trigger); 332 } 333 unset($item['triggers']); 334 } 335 } 336 } 337 } 338 } 339 340 return $simple_triggers; 341 } 342 343 /** 344 * Get triggers from the imported data. 345 * 346 * @return array 347 */ 348 public function getTriggers() { 349 $triggers = []; 350 351 if (array_key_exists('triggers', $this->data)) { 352 foreach ($this->data['triggers'] as $trigger) { 353 $triggers[] = $this->renameTriggerFields($trigger); 354 } 355 } 356 357 return array_merge($triggers, $this->getSimpleTriggers()); 358 } 359 360 /** 361 * Get images from the imported data. 362 * 363 * @return array 364 */ 365 public function getImages() { 366 $images = []; 367 368 if (array_key_exists('images', $this->data)) { 369 foreach ($this->data['images'] as $image) { 370 $images[] = CArrayHelper::renameKeys($image, ['encodedImage' => 'image']); 371 } 372 } 373 374 return $images; 375 } 376 377 /** 378 * Get maps from the imported data. 379 * 380 * @return array 381 */ 382 public function getMaps() { 383 return array_key_exists('maps', $this->data) ? $this->data['maps'] : []; 384 } 385 386 /** 387 * Get screens from the imported data. 388 * 389 * @return array 390 */ 391 public function getScreens() { 392 $screens = []; 393 394 if (array_key_exists('screens', $this->data)) { 395 foreach ($this->data['screens'] as $screen) { 396 $screens[] = CArrayHelper::renameKeys($screen, ['screen_items' => 'screenitems']); 397 } 398 } 399 400 return $screens; 401 } 402 403 /** 404 * Get template screens from the imported data. 405 * 406 * @return array 407 */ 408 public function getTemplateScreens() { 409 $screens = []; 410 411 if (array_key_exists('templates', $this->data)) { 412 foreach ($this->data['templates'] as $template) { 413 if (array_key_exists('screens', $template)) { 414 foreach ($template['screens'] as $screen) { 415 $screens[$template['template']][$screen['name']] = 416 CArrayHelper::renameKeys($screen, ['screen_items' => 'screenitems']); 417 } 418 } 419 } 420 } 421 422 return $screens; 423 } 424 425 /** 426 * Get media types from the imported data. 427 * 428 * @return array 429 */ 430 public function getMediaTypes() { 431 $media_types = []; 432 433 if (array_key_exists('media_types', $this->data)) { 434 $keys = [ 435 'password' => 'passwd', 436 'script_name' => 'exec_path', 437 'max_sessions' => 'maxsessions', 438 'attempts' => 'maxattempts' 439 ]; 440 441 $message_template_keys = [ 442 'event_source' => 'eventsource', 443 'operation_mode' => 'recovery' 444 ]; 445 446 foreach ($this->data['media_types'] as $media_type) { 447 if (array_key_exists('message_templates', $media_type)) { 448 foreach ($media_type['message_templates'] as &$message_template) { 449 $message_template = CArrayHelper::renameKeys($message_template, $message_template_keys); 450 } 451 unset($message_template); 452 } 453 454 if ($media_type['type'] == MEDIA_TYPE_EXEC && array_key_exists('parameters', $media_type)) { 455 $media_type['exec_params'] = $media_type['parameters'] 456 ? implode("\n", $media_type['parameters'])."\n" 457 : ''; 458 unset($media_type['parameters']); 459 } 460 461 $media_types[] = CArrayHelper::renameKeys($media_type, $keys); 462 } 463 } 464 465 return $media_types; 466 } 467 468 /** 469 * Enriches trigger expression and trigger recovery expression with host:item pair. 470 * 471 * @param string $host 472 * @param string $item_key 473 * @param array $simple_trigger 474 * @param string $simple_trigger['expression] 475 * @param int $simple_trigger['recovery_mode] 476 * @param string $simple_trigger['recovery_expression] 477 * @param array $options 478 * @param bool $options['lldmacros'] (optional) 479 * @param bool $options['allow_func_only'] (optional) 480 * 481 * @return array 482 */ 483 protected function enrichSimpleTriggerExpression($host, $item_key, array $simple_trigger, array $options) { 484 $expression_data = new CTriggerExpression($options); 485 $prefix = $host.':'.$item_key.'.'; 486 487 if ($expression_data->parse($simple_trigger['expression'])) { 488 foreach (array_reverse($expression_data->expressions) as $expression) { 489 if ($expression['host'] === '' && $expression['item'] === '') { 490 $simple_trigger['expression'] = substr_replace($simple_trigger['expression'], $prefix, 491 $expression['pos'] + 1, 0 492 ); 493 } 494 } 495 } 496 497 if ($simple_trigger['recovery_mode'] == ZBX_RECOVERY_MODE_RECOVERY_EXPRESSION 498 && $expression_data->parse($simple_trigger['recovery_expression'])) { 499 foreach (array_reverse($expression_data->expressions) as $expression) { 500 if ($expression['host'] === '' && $expression['item'] === '') { 501 $simple_trigger['recovery_expression'] = substr_replace($simple_trigger['recovery_expression'], 502 $prefix, $expression['pos'] + 1, 0 503 ); 504 } 505 } 506 } 507 508 return $simple_trigger; 509 } 510 511 /** 512 * Format discovery rule. 513 * 514 * @param array $discovery_rule 515 * @param string $host 516 * 517 * @return array 518 */ 519 protected function formatDiscoveryRule(array $discovery_rule, $host) { 520 $discovery_rule = $this->renameItemFields($discovery_rule); 521 $discovery_rule = $this->formatDiscoveryRuleOverrideFields($discovery_rule); 522 523 foreach ($discovery_rule['item_prototypes'] as &$item_prototype) { 524 if (array_key_exists('trigger_prototypes', $item_prototype)) { 525 foreach ($item_prototype['trigger_prototypes'] as $trigger_prototype) { 526 $discovery_rule['trigger_prototypes'][] = $this->enrichSimpleTriggerExpression($host, 527 $item_prototype['key'], $trigger_prototype, ['allow_func_only' => true] 528 ); 529 } 530 unset($item_prototype['trigger_prototypes']); 531 } 532 533 $item_prototype = $this->renameItemFields($item_prototype); 534 } 535 unset($item_prototype); 536 537 foreach ($discovery_rule['trigger_prototypes'] as &$trigger_prototype) { 538 $trigger_prototype = $this->renameTriggerFields($trigger_prototype); 539 } 540 unset($trigger_prototype); 541 542 foreach ($discovery_rule['graph_prototypes'] as &$graph_prototype) { 543 $graph_prototype = $this->renameGraphFields($graph_prototype); 544 } 545 unset($graph_prototype); 546 547 return $discovery_rule; 548 } 549 550 /** 551 * Format low-level disovery rule overrides. 552 * 553 * @param array $discovery_rule Data of single low-level discovery rule. 554 * 555 * @return array 556 */ 557 protected function formatDiscoveryRuleOverrideFields(array $discovery_rule) { 558 if ($discovery_rule['overrides']) { 559 foreach ($discovery_rule['overrides'] as &$override) { 560 if (!$override['filter']) { 561 unset($override['filter']); 562 } 563 564 foreach ($override['operations'] as &$operation) { 565 if (array_key_exists('discover', $operation) && $operation['discover'] !== '') { 566 $operation['opdiscover']['discover'] = $operation['discover']; 567 } 568 569 switch ($operation['operationobject']) { 570 case OPERATION_OBJECT_ITEM_PROTOTYPE: 571 if (array_key_exists('status', $operation) && $operation['status'] !== '') { 572 $operation['opstatus']['status'] = $operation['status']; 573 } 574 if (array_key_exists('delay', $operation) && $operation['delay'] !== '') { 575 $operation['opperiod']['delay'] = $operation['delay']; 576 } 577 if (array_key_exists('history', $operation) && $operation['history'] !== '') { 578 $operation['ophistory']['history'] = $operation['history']; 579 } 580 if (array_key_exists('trends', $operation) && $operation['trends'] !== '') { 581 $operation['optrends']['trends'] = $operation['trends']; 582 } 583 break; 584 585 case OPERATION_OBJECT_TRIGGER_PROTOTYPE: 586 if (array_key_exists('status', $operation) && $operation['status'] !== '') { 587 $operation['opstatus']['status'] = $operation['status']; 588 } 589 if (array_key_exists('severity', $operation) && $operation['severity'] !== '') { 590 $operation['opseverity']['severity'] = $operation['severity']; 591 } 592 if (array_key_exists('tags', $operation) && $operation['tags']) { 593 $operation['optag'] = []; 594 foreach ($operation['tags'] as $tag) { 595 $operation['optag'][] = $tag; 596 } 597 } 598 break; 599 600 case OPERATION_OBJECT_HOST_PROTOTYPE: 601 if (array_key_exists('status', $operation) && $operation['status'] !== '') { 602 $operation['opstatus']['status'] = $operation['status']; 603 } 604 if (array_key_exists('templates', $operation) && $operation['templates']) { 605 $operation['optemplate'] = []; 606 foreach ($operation['templates'] as $template) { 607 $operation['optemplate'][] = $template; 608 } 609 } 610 if (array_key_exists('inventory_mode', $operation) && $operation['inventory_mode'] !== '') { 611 $operation['opinventory']['inventory_mode'] = $operation['inventory_mode']; 612 } 613 break; 614 } 615 616 unset($operation['status'], $operation['discover'], $operation['delay'], $operation['history'], 617 $operation['trends'], $operation['severity'], $operation['tags'], $operation['templates'], 618 $operation['inventory_mode'] 619 ); 620 } 621 unset($operation); 622 } 623 unset($override); 624 } 625 626 return $discovery_rule; 627 } 628 629 /** 630 * Rename items, discovery rules, item prototypes fields. 631 * 632 * @param array $item 633 * 634 * @return array 635 */ 636 protected function renameItemFields(array $item) { 637 return CArrayHelper::renameKeys($item, ['key' => 'key_', 'allowed_hosts' => 'trapper_hosts']); 638 } 639 640 /** 641 * Format web scenario. 642 * 643 * @param array $httptest 644 * 645 * @return array 646 */ 647 protected function formatHttpTest(array $httptest) { 648 $httptest = $this->renameHttpTestFields($httptest); 649 650 $no = 0; 651 foreach ($httptest['steps'] as &$step) { 652 $step['no'] = ++$no; 653 } 654 unset($step); 655 656 return $httptest; 657 } 658 659 /** 660 * Rename web scenarios fields. 661 * 662 * @param array $httptest 663 * 664 * @return array 665 */ 666 protected function renameHttpTestFields(array $httptest) { 667 return CArrayHelper::renameKeys($httptest, ['attempts' => 'retries']); 668 } 669 670 /** 671 * Rename triggers, trigger prototypes fields. 672 * 673 * @param array $trigger 674 * 675 * @return array 676 */ 677 protected function renameTriggerFields(array $trigger) { 678 $trigger = CArrayHelper::renameKeys($trigger, ['description' => 'comments']); 679 680 return CArrayHelper::renameKeys($trigger, ['name' => 'description', 'severity' => 'priority']); 681 } 682 683 /** 684 * Rename graphs, graph prototypes fields. 685 * 686 * @param array $graph 687 * 688 * @return array 689 */ 690 protected function renameGraphFields(array $graph) { 691 return CArrayHelper::renameKeys($graph, [ 692 'type' => 'graphtype', 693 'ymin_type_1' => 'ymin_type', 694 'ymax_type_1' => 'ymax_type', 695 'graph_items' => 'gitems' 696 ]); 697 } 698} 699