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 22class CConfigurationExportBuilder { 23 24 /** 25 * @var array 26 */ 27 protected $data = []; 28 29 /** 30 * @param $version current export version 31 */ 32 public function __construct() { 33 $this->data['version'] = ZABBIX_EXPORT_VERSION; 34 $this->data['date'] = date(DATE_TIME_FORMAT_SECONDS_XML, time() - date('Z')); 35 } 36 37 /** 38 * Get array with formatted export data. 39 * 40 * @return array 41 */ 42 public function getExport() { 43 return ['zabbix_export' => $this->data]; 44 } 45 46 /** 47 * Build data structure. 48 * 49 * @param array $schema Tag schema from validation class. 50 * @param array $data Export data. 51 * @param string $main_tag Main element (for error reporting). 52 * 53 * @return array 54 */ 55 protected function build(array $schema, array $data, $main_tag = null) { 56 $n = 0; 57 $result = []; 58 59 $rules = $schema['rules']; 60 61 if ($schema['type'] & XML_INDEXED_ARRAY) { 62 $rules = $schema['rules'][$schema['prefix']]['rules']; 63 } 64 65 foreach ($data as $row) { 66 $store = []; 67 foreach ($rules as $tag => $val) { 68 $is_required = $val['type'] & XML_REQUIRED; 69 $is_string = $val['type'] & XML_STRING; 70 $is_array = $val['type'] & XML_ARRAY; 71 $is_indexed_array = $val['type'] & XML_INDEXED_ARRAY; 72 $has_data = array_key_exists($tag, $row); 73 74 if (array_key_exists('ex_default', $val)) { 75 $default_value = (string) call_user_func($val['ex_default'], $row); 76 } 77 elseif (array_key_exists('default', $val)) { 78 $default_value = (string) $val['default']; 79 } 80 else { 81 $default_value = null; 82 } 83 84 if (!$default_value && !$has_data) { 85 if ($is_required) { 86 throw new Exception(_s('Invalid tag "%1$s": %2$s.', $main_tag, 87 _s('the tag "%1$s" is missing', $tag) 88 )); 89 } 90 continue; 91 } 92 93 $value = $has_data ? $row[$tag] : $default_value; 94 95 if (!$is_required && $has_data && $default_value == $value) { 96 continue; 97 } 98 99 if (array_key_exists('export', $val)) { 100 $store[$tag] = call_user_func($val['export'], $row); 101 continue; 102 } 103 104 if (($is_indexed_array || $is_array) && $has_data) { 105 $temp_store = $this->build($val, $is_array ? [$value] : $value, $tag); 106 if ($is_required || $temp_store) { 107 $store[$tag] = $temp_store; 108 } 109 continue; 110 } 111 112 if ($is_string && $value !== null) { 113 $value = str_replace("\r\n", "\n", $value); 114 } 115 116 if (array_key_exists('in', $val)) { 117 if (!array_key_exists($value, $val['in'])) { 118 throw new Exception(_s('Invalid tag "%1$s": %2$s.', $tag, 119 _s('unexpected constant value "%1$s"', $value) 120 )); 121 } 122 123 $store[$tag] = $val['in'][$value]; 124 } 125 else { 126 $store[$tag] = $value; 127 } 128 } 129 130 if ($schema['type'] & XML_INDEXED_ARRAY) { 131 $result[$n++] = $store; 132 } 133 else { 134 $result = $store; 135 } 136 } 137 138 return $result; 139 } 140 141 /** 142 * Format groups. 143 * 144 * @param array $schema Tag schema from validation class. 145 * @param array $groups Export data. 146 */ 147 public function buildGroups(array $schema, array $groups) { 148 $groups = $this->formatGroups($groups); 149 150 $this->data['groups'] = $this->build($schema, $groups, 'groups'); 151 } 152 153 /** 154 * Format templates. 155 * 156 * @param array $schema Tag schema from validation class. 157 * @param array $templates Export data. 158 * @param array $simple_triggers Simple triggers. 159 */ 160 public function buildTemplates(array $schema, array $templates, array $simple_triggers) { 161 $templates = $this->formatTemplates($templates, $simple_triggers); 162 163 $this->data['templates'] = $this->build($schema, $templates, 'templates'); 164 } 165 166 /** 167 * Format hosts. 168 * 169 * @param array $schema Tag schema from validation class. 170 * @param array $hosts Export data. 171 * @param array $simple_triggers Simple triggers. 172 */ 173 public function buildHosts(array $schema, array $hosts, array $simple_triggers) { 174 $hosts = $this->formatHosts($hosts, $simple_triggers); 175 176 $this->data['hosts'] = $this->build($schema, $hosts, 'hosts'); 177 } 178 179 /** 180 * Format triggers. 181 * 182 * @param array $schema Tag schema from validation class. 183 * @param array $triggers Export data. 184 */ 185 public function buildTriggers(array $schema, array $triggers) { 186 $triggers = $this->formatTriggers($triggers); 187 188 $this->data['triggers'] = $this->build($schema, $triggers, 'triggers'); 189 } 190 191 /** 192 * Format graphs. 193 * 194 * @param array $schema Tag schema from validation class. 195 * @param array $graphs Export data. 196 */ 197 public function buildGraphs(array $schema, array $graphs) { 198 $graphs = $this->formatGraphs($graphs); 199 200 $this->data['graphs'] = $this->build($schema, $graphs, 'graphs'); 201 } 202 203 /** 204 * Format media types. 205 * 206 * @param array $schema Tag schema from validation class. 207 * @param array $media_types Export data. 208 */ 209 public function buildMediaTypes(array $schema, array $media_types) { 210 $media_types = $this->formatMediaTypes($media_types); 211 212 $this->data['media_types'] = $this->build($schema, $media_types, 'media_types'); 213 } 214 215 /** 216 * Separate simple triggers. 217 * 218 * @param array $triggers 219 * 220 * @return array 221 */ 222 public function extractSimpleTriggers(array &$triggers) { 223 $simple_triggers = []; 224 225 foreach ($triggers as $triggerid => $trigger) { 226 if (count($trigger['items']) == 1 && $trigger['items'][0]['type'] != ITEM_TYPE_HTTPTEST 227 && $trigger['items'][0]['templateid'] == 0) { 228 $simple_triggers[] = $trigger; 229 unset($triggers[$triggerid]); 230 } 231 } 232 233 return $simple_triggers; 234 } 235 236 /** 237 * Format templates. 238 * 239 * @param array $templates 240 * @param array $simple_triggers 241 */ 242 protected function formatTemplates(array $templates, array $simple_triggers = null) { 243 $result = []; 244 245 CArrayHelper::sort($templates, ['host']); 246 247 foreach ($templates as $template) { 248 $result[] = [ 249 'uuid' => $template['uuid'], 250 'template' => $template['host'], 251 'name' => $template['name'], 252 'description' => $template['description'], 253 'groups' => $this->formatGroups($template['groups']), 254 'items' => $this->formatItems($template['items'], $simple_triggers), 255 'discovery_rules' => $this->formatDiscoveryRules($template['discoveryRules']), 256 'httptests' => $this->formatHttpTests($template['httptests']), 257 'macros' => $this->formatMacros($template['macros']), 258 'templates' => $this->formatTemplateLinkage($template['parentTemplates']), 259 'dashboards' => $this->formatDashboards($template['dashboards']), 260 'tags' => $this->formatTags($template['tags']), 261 'valuemaps' => $this->formatValueMaps($template['valuemaps']) 262 ]; 263 } 264 265 return $result; 266 } 267 268 /** 269 * Format hosts. 270 * 271 * @param array $hosts 272 * @param array $simple_triggers 273 */ 274 protected function formatHosts(array $hosts, array $simple_triggers = null) { 275 $result = []; 276 277 CArrayHelper::sort($hosts, ['host']); 278 279 foreach ($hosts as $host) { 280 $host = $this->createInterfaceReferences($host); 281 282 $result[] = [ 283 'host' => $host['host'], 284 'name' => $host['name'], 285 'description' => $host['description'], 286 'proxy' => $host['proxy'], 287 'status' => $host['status'], 288 'ipmi_authtype' => $host['ipmi_authtype'], 289 'ipmi_privilege' => $host['ipmi_privilege'], 290 'ipmi_username' => $host['ipmi_username'], 291 'ipmi_password' => $host['ipmi_password'], 292 'templates' => $this->formatTemplateLinkage($host['parentTemplates']), 293 'groups' => $this->formatGroups($host['groups']), 294 'interfaces' => $this->formatHostInterfaces($host['interfaces']), 295 'items' => $this->formatItems($host['items'], $simple_triggers), 296 'discovery_rules' => $this->formatDiscoveryRules($host['discoveryRules']), 297 'httptests' => $this->formatHttpTests($host['httptests']), 298 'macros' => $this->formatMacros($host['macros']), 299 'inventory_mode' => $host['inventory_mode'], 300 'inventory' => $this->formatHostInventory($host['inventory']), 301 'tags' => $this->formatTags($host['tags']), 302 'valuemaps' => $this->formatValueMaps($host['valuemaps']) 303 ]; 304 } 305 306 return $result; 307 } 308 309 /** 310 * Format images. 311 * 312 * @param array $images 313 */ 314 public function buildImages(array $images) { 315 $this->data['images'] = []; 316 317 foreach ($images as $image) { 318 $this->data['images'][] = [ 319 'name' => $image['name'], 320 'imagetype' => $image['imagetype'], 321 'encodedImage' => $image['encodedImage'] 322 ]; 323 } 324 } 325 326 /** 327 * Format maps. 328 * 329 * @param array $schema Tag schema from validation class. 330 * @param array $maps Export data. 331 */ 332 public function buildMaps(array $schema, array $maps) { 333 $this->data['maps'] = []; 334 335 CArrayHelper::sort($maps, ['name']); 336 337 foreach ($maps as $map) { 338 $tmpSelements = $this->formatMapElements($map['selements']); 339 $this->data['maps'][] = [ 340 'name' => $map['name'], 341 'width' => $map['width'], 342 'height' => $map['height'], 343 'label_type' => $map['label_type'], 344 'label_location' => $map['label_location'], 345 'highlight' => $map['highlight'], 346 'expandproblem' => $map['expandproblem'], 347 'markelements' => $map['markelements'], 348 'show_unack' => $map['show_unack'], 349 'severity_min' => $map['severity_min'], 350 'show_suppressed' => $map['show_suppressed'], 351 'grid_size' => $map['grid_size'], 352 'grid_show' => $map['grid_show'], 353 'grid_align' => $map['grid_align'], 354 'label_format' => $map['label_format'], 355 'label_type_host' => $map['label_type_host'], 356 'label_type_hostgroup' => $map['label_type_hostgroup'], 357 'label_type_trigger' => $map['label_type_trigger'], 358 'label_type_map' => $map['label_type_map'], 359 'label_type_image' => $map['label_type_image'], 360 'label_string_host' => $map['label_string_host'], 361 'label_string_hostgroup' => $map['label_string_hostgroup'], 362 'label_string_trigger' => $map['label_string_trigger'], 363 'label_string_map' => $map['label_string_map'], 364 'label_string_image' => $map['label_string_image'], 365 'expand_macros' => $map['expand_macros'], 366 'background' => $map['backgroundid'], 367 'iconmap' => $map['iconmap'], 368 'urls' => $this->formatMapUrls($map['urls']), 369 'selements' => $tmpSelements, 370 'shapes' => $map['shapes'], 371 'lines' => $map['lines'], 372 'links' => $this->formatMapLinks($map['links'], $tmpSelements) 373 ]; 374 } 375 376 $this->data['maps'] = $this->build($schema, $this->data['maps'], 'maps'); 377 } 378 379 /** 380 * Format media types. 381 * 382 * @param array $media_types 383 */ 384 protected function formatMediaTypes(array $media_types) { 385 $result = []; 386 387 CArrayHelper::sort($media_types, ['name']); 388 389 foreach ($media_types as $media_type) { 390 $result[] = [ 391 'name' => $media_type['name'], 392 'type' => $media_type['type'], 393 'smtp_server' => $media_type['smtp_server'], 394 'smtp_port' => $media_type['smtp_port'], 395 'smtp_helo' => $media_type['smtp_helo'], 396 'smtp_email' => $media_type['smtp_email'], 397 'smtp_security' => $media_type['smtp_security'], 398 'smtp_verify_host' => $media_type['smtp_verify_host'], 399 'smtp_verify_peer' => $media_type['smtp_verify_peer'], 400 'smtp_authentication' => $media_type['smtp_authentication'], 401 'username' => $media_type['username'], 402 'password' => $media_type['passwd'], 403 'content_type' => $media_type['content_type'], 404 'script_name' => $media_type['exec_path'], 405 'parameters' => self::formatMediaTypeParameters($media_type), 406 'gsm_modem' => $media_type['gsm_modem'], 407 'status' => $media_type['status'], 408 'max_sessions' => $media_type['maxsessions'], 409 'attempts' => $media_type['maxattempts'], 410 'attempt_interval' => $media_type['attempt_interval'], 411 'script' => $media_type['script'], 412 'timeout' => $media_type['timeout'], 413 'process_tags' => $media_type['process_tags'], 414 'show_event_menu' => $media_type['show_event_menu'], 415 'event_menu_url' => $media_type['event_menu_url'], 416 'event_menu_name' => $media_type['event_menu_name'], 417 'description' => $media_type['description'], 418 'message_templates' => self::formatMediaTypeMessageTemplates($media_type['message_templates']) 419 ]; 420 } 421 422 return $result; 423 } 424 425 /** 426 * Format media type parameters. 427 * 428 * @static 429 * 430 * @param array $media_type 431 * 432 * @return array|string 433 */ 434 private static function formatMediaTypeParameters(array $media_type) { 435 if ($media_type['type'] == MEDIA_TYPE_EXEC) { 436 return $media_type['exec_params']; 437 } 438 439 if ($media_type['type'] == MEDIA_TYPE_WEBHOOK) { 440 CArrayHelper::sort($media_type['parameters'], ['name']); 441 442 return array_values($media_type['parameters']); 443 } 444 445 return []; 446 } 447 448 /** 449 * Format media type message templates. 450 * 451 * @static 452 * 453 * @param array $message_templates 454 * 455 * @return array 456 */ 457 private static function formatMediaTypeMessageTemplates(array $message_templates): array { 458 $result = []; 459 460 CArrayHelper::sort($message_templates, ['eventsource', 'recovery']); 461 462 foreach ($message_templates as $message_template) { 463 $result[] = [ 464 'event_source' => $message_template['eventsource'], 465 'operation_mode' => $message_template['recovery'], 466 'subject' => $message_template['subject'], 467 'message' => $message_template['message'] 468 ]; 469 } 470 471 return $result; 472 } 473 474 /** 475 * Format value maps. 476 * 477 * @param array $valuemaps 478 */ 479 protected function formatValueMaps(array $valuemaps) { 480 CArrayHelper::sort($valuemaps, ['name']); 481 482 foreach ($valuemaps as &$valuemap) { 483 foreach ($valuemap['mappings'] as &$mapping) { 484 if ($mapping['type'] == VALUEMAP_MAPPING_TYPE_EQUAL) { 485 unset($mapping['type']); 486 } 487 elseif ($mapping['type'] == VALUEMAP_MAPPING_TYPE_DEFAULT) { 488 unset($mapping['value']); 489 } 490 } 491 unset($mapping); 492 } 493 unset($valuemap); 494 495 return $valuemaps; 496 } 497 498 /** 499 * For each host interface an unique reference must be created and then added for all items, discovery rules 500 * and item prototypes that use the interface. 501 * 502 * @param array $host 503 * 504 * @return array 505 */ 506 protected function createInterfaceReferences(array $host) { 507 $references = [ 508 'num' => 1, 509 'refs' => [] 510 ]; 511 512 // create interface references 513 foreach ($host['interfaces'] as &$interface) { 514 $refNum = $references['num']++; 515 $referenceKey = 'if'.$refNum; 516 $interface['interface_ref'] = $referenceKey; 517 $references['refs'][$interface['interfaceid']] = $referenceKey; 518 } 519 unset($interface); 520 521 foreach ($host['items'] as &$item) { 522 if ($item['interfaceid']) { 523 $item['interface_ref'] = $references['refs'][$item['interfaceid']]; 524 } 525 } 526 unset($item); 527 528 foreach ($host['discoveryRules'] as &$discoveryRule) { 529 if ($discoveryRule['interfaceid']) { 530 $discoveryRule['interface_ref'] = $references['refs'][$discoveryRule['interfaceid']]; 531 } 532 533 foreach ($discoveryRule['itemPrototypes'] as &$prototype) { 534 if ($prototype['interfaceid']) { 535 $prototype['interface_ref'] = $references['refs'][$prototype['interfaceid']]; 536 } 537 } 538 unset($prototype); 539 } 540 unset($discoveryRule); 541 542 return $host; 543 } 544 545 /** 546 * Format discovery rules. 547 * 548 * @param array $discoveryRules 549 * 550 * @return array 551 */ 552 protected function formatDiscoveryRules(array $discoveryRules) { 553 $result = []; 554 555 CArrayHelper::sort($discoveryRules, ['key_']); 556 557 $simple_trigger_prototypes = []; 558 559 foreach ($discoveryRules as $discoveryRule) { 560 foreach ($discoveryRule['triggerPrototypes'] as $i => $trigger_prototype) { 561 if (count($trigger_prototype['items']) == 1) { 562 $simple_trigger_prototypes[] = $trigger_prototype; 563 unset($discoveryRule['triggerPrototypes'][$i]); 564 } 565 } 566 567 $data = [ 568 'uuid' => $discoveryRule['uuid'], 569 'name' => $discoveryRule['name'], 570 'type' => $discoveryRule['type'], 571 'snmp_oid' => $discoveryRule['snmp_oid'], 572 'key' => $discoveryRule['key_'], 573 'delay' => $discoveryRule['delay'], 574 'status' => $discoveryRule['status'], 575 'allowed_hosts' => $discoveryRule['trapper_hosts'], 576 'params' => $discoveryRule['params'], 577 'ipmi_sensor' => $discoveryRule['ipmi_sensor'], 578 'authtype' => $discoveryRule['authtype'], 579 'username' => $discoveryRule['username'], 580 'password' => $discoveryRule['password'], 581 'publickey' => $discoveryRule['publickey'], 582 'privatekey' => $discoveryRule['privatekey'], 583 'filter' => $discoveryRule['filter'], 584 'lifetime' => $discoveryRule['lifetime'], 585 'description' => $discoveryRule['description'], 586 'item_prototypes' => $this->formatItems($discoveryRule['itemPrototypes'], $simple_trigger_prototypes), 587 'trigger_prototypes' => $this->formatTriggers($discoveryRule['triggerPrototypes']), 588 'graph_prototypes' => $this->formatGraphs($discoveryRule['graphPrototypes']), 589 'host_prototypes' => $this->formatHostPrototypes($discoveryRule['hostPrototypes']), 590 'jmx_endpoint' => $discoveryRule['jmx_endpoint'], 591 'timeout' => $discoveryRule['timeout'], 592 'url' => $discoveryRule['url'], 593 'query_fields' => $discoveryRule['query_fields'], 594 'parameters' => $discoveryRule['parameters'], 595 'posts' => $discoveryRule['posts'], 596 'status_codes' => $discoveryRule['status_codes'], 597 'follow_redirects' => $discoveryRule['follow_redirects'], 598 'post_type' => $discoveryRule['post_type'], 599 'http_proxy' => $discoveryRule['http_proxy'], 600 'headers' => $discoveryRule['headers'], 601 'retrieve_mode' => $discoveryRule['retrieve_mode'], 602 'request_method' => $discoveryRule['request_method'], 603 'allow_traps' => $discoveryRule['allow_traps'], 604 'ssl_cert_file' => $discoveryRule['ssl_cert_file'], 605 'ssl_key_file' => $discoveryRule['ssl_key_file'], 606 'ssl_key_password' => $discoveryRule['ssl_key_password'], 607 'verify_peer' => $discoveryRule['verify_peer'], 608 'verify_host' => $discoveryRule['verify_host'], 609 'lld_macro_paths' => $discoveryRule['lld_macro_paths'], 610 'preprocessing' => self::formatPreprocessingSteps($discoveryRule['preprocessing']), 611 'overrides' => $discoveryRule['overrides'] 612 ]; 613 614 if (isset($discoveryRule['interface_ref'])) { 615 $data['interface_ref'] = $discoveryRule['interface_ref']; 616 } 617 618 if ($discoveryRule['query_fields']) { 619 $query_fields = []; 620 621 foreach ($discoveryRule['query_fields'] as $query_field) { 622 $query_fields[] = [ 623 'name' => key($query_field), 624 'value' => reset($query_field) 625 ]; 626 } 627 628 $data['query_fields'] = $query_fields; 629 } 630 631 if ($discoveryRule['headers']) { 632 $headers = []; 633 634 foreach ($discoveryRule['headers'] as $name => $value) { 635 $headers[] = compact('name', 'value'); 636 } 637 638 $data['headers'] = $headers; 639 } 640 641 $data['master_item'] = ($discoveryRule['type'] == ITEM_TYPE_DEPENDENT) 642 ? ['key' => $discoveryRule['master_item']['key_']] 643 : []; 644 645 $result[] = $data; 646 } 647 648 return $result; 649 } 650 651 /** 652 * Format preprocessing steps. 653 * 654 * @param array $preprocessing_steps 655 * 656 * @static 657 * 658 * @return array 659 */ 660 private static function formatPreprocessingSteps(array $preprocessing_steps) { 661 foreach ($preprocessing_steps as &$preprocessing_step) { 662 $preprocessing_step['parameters'] = ($preprocessing_step['type'] == ZBX_PREPROC_SCRIPT) 663 ? [$preprocessing_step['params']] 664 : explode("\n", $preprocessing_step['params']); 665 unset($preprocessing_step['params']); 666 } 667 unset($preprocessing_step); 668 669 return $preprocessing_steps; 670 } 671 672 /** 673 * Format web scenarios. 674 * 675 * @param array $httptests 676 * 677 * @return array 678 */ 679 protected function formatHttpTests(array $httptests) { 680 $result = []; 681 682 order_result($httptests, 'name'); 683 684 foreach ($httptests as $httptest) { 685 $result[] = [ 686 'uuid' => $httptest['uuid'], 687 'name' => $httptest['name'], 688 'delay' => $httptest['delay'], 689 'attempts' => $httptest['retries'], 690 'agent' => $httptest['agent'], 691 'http_proxy' => $httptest['http_proxy'], 692 'variables' => $httptest['variables'], 693 'headers' => $httptest['headers'], 694 'status' => $httptest['status'], 695 'authentication' => $httptest['authentication'], 696 'http_user' => $httptest['http_user'], 697 'http_password' => $httptest['http_password'], 698 'verify_peer' => $httptest['verify_peer'], 699 'verify_host' => $httptest['verify_host'], 700 'ssl_cert_file' => $httptest['ssl_cert_file'], 701 'ssl_key_file' => $httptest['ssl_key_file'], 702 'ssl_key_password' => $httptest['ssl_key_password'], 703 'steps' => $this->formatHttpSteps($httptest['steps']), 704 'tags' => $this->formatTags($httptest['tags']) 705 ]; 706 } 707 708 return $result; 709 } 710 711 /** 712 * Format web scenario steps. 713 * 714 * @param array $httpsteps 715 * 716 * @return array 717 */ 718 protected function formatHttpSteps(array $httpsteps) { 719 $result = []; 720 721 order_result($httpsteps, 'no'); 722 723 foreach ($httpsteps as $httpstep) { 724 $result[] = [ 725 'name' => $httpstep['name'], 726 'url' => $httpstep['url'], 727 'query_fields' => $httpstep['query_fields'], 728 'posts' => $httpstep['posts'], 729 'variables' => $httpstep['variables'], 730 'headers' => $httpstep['headers'], 731 'follow_redirects' => $httpstep['follow_redirects'], 732 'retrieve_mode' => $httpstep['retrieve_mode'], 733 'timeout' => $httpstep['timeout'], 734 'required' => $httpstep['required'], 735 'status_codes' => $httpstep['status_codes'] 736 ]; 737 } 738 739 return $result; 740 } 741 742 /** 743 * Format host inventory. 744 * 745 * @param array $inventory 746 * 747 * @return array 748 */ 749 protected function formatHostInventory(array $inventory) { 750 unset($inventory['hostid']); 751 752 return $inventory; 753 } 754 755 /** 756 * Format graphs. 757 * 758 * @param array $graphs 759 * 760 * @return array 761 */ 762 protected function formatGraphs(array $graphs) { 763 $result = []; 764 765 CArrayHelper::sort($graphs, ['name']); 766 767 foreach ($graphs as $graph) { 768 $data = [ 769 'name' => $graph['name'], 770 'width' => $graph['width'], 771 'height' => $graph['height'], 772 'yaxismin' => $graph['yaxismin'], 773 'yaxismax' => $graph['yaxismax'], 774 'show_work_period' => $graph['show_work_period'], 775 'show_triggers' => $graph['show_triggers'], 776 'type' => $graph['graphtype'], 777 'show_legend' => $graph['show_legend'], 778 'show_3d' => $graph['show_3d'], 779 'percent_left' => $graph['percent_left'], 780 'percent_right' => $graph['percent_right'], 781 'ymin_type_1' => $graph['ymin_type'], 782 'ymax_type_1' => $graph['ymax_type'], 783 'ymin_item_1' => $graph['ymin_itemid'], 784 'ymax_item_1' => $graph['ymax_itemid'], 785 'graph_items' => $this->formatGraphItems($graph['gitems']) 786 ]; 787 788 if (array_key_exists('uuid', $graph)) { 789 $data['uuid'] = $graph['uuid']; 790 } 791 792 if ($graph['flags'] == ZBX_FLAG_DISCOVERY_PROTOTYPE) { 793 $data['discover'] = $graph['discover']; 794 } 795 796 $result[] = $data; 797 } 798 799 return $result; 800 } 801 802 /** 803 * Format host prototypes. 804 * 805 * @param array $hostPrototypes 806 * 807 * @return array 808 */ 809 protected function formatHostPrototypes(array $hostPrototypes) { 810 $result = []; 811 812 CArrayHelper::sort($hostPrototypes, ['host']); 813 814 foreach ($hostPrototypes as $hostPrototype) { 815 $result[] = [ 816 'uuid' => $hostPrototype['uuid'], 817 'host' => $hostPrototype['host'], 818 'name' => $hostPrototype['name'], 819 'status' => $hostPrototype['status'], 820 'discover' => $hostPrototype['discover'], 821 'group_links' => $this->formatGroupLinks($hostPrototype['groupLinks']), 822 'group_prototypes' => $this->formatGroupPrototypes($hostPrototype['groupPrototypes']), 823 'macros' => $this->formatMacros($hostPrototype['macros']), 824 'tags' => $this->formatTags($hostPrototype['tags']), 825 'templates' => $this->formatTemplateLinkage($hostPrototype['templates']), 826 'inventory_mode' => $hostPrototype['inventory_mode'], 827 'custom_interfaces' => $hostPrototype['custom_interfaces'], 828 'interfaces' => $this->formatHostPrototypeInterfaces($hostPrototype['interfaces']) 829 ]; 830 } 831 832 return $result; 833 } 834 835 /** 836 * Format group links. 837 * 838 * @param array $groupLinks 839 * 840 * @return array 841 */ 842 protected function formatGroupLinks(array $groupLinks) { 843 $result = []; 844 845 CArrayHelper::sort($groupLinks, ['name']); 846 847 foreach ($groupLinks as $groupLink) { 848 $result[] = [ 849 'group' => $groupLink['groupid'] 850 ]; 851 } 852 853 return $result; 854 } 855 856 /** 857 * Format group prototypes. 858 * 859 * @param array $groupPrototypes 860 * 861 * @return array 862 */ 863 protected function formatGroupPrototypes(array $groupPrototypes) { 864 $result = []; 865 866 CArrayHelper::sort($groupPrototypes, ['name']); 867 868 foreach ($groupPrototypes as $groupPrototype) { 869 $result[] = [ 870 'name' => $groupPrototype['name'] 871 ]; 872 } 873 874 return $result; 875 } 876 877 /** 878 * Format template linkage. 879 * 880 * @param array $templates 881 * 882 * @return array 883 */ 884 protected function formatTemplateLinkage(array $templates) { 885 $result = []; 886 887 CArrayHelper::sort($templates, ['host']); 888 889 foreach ($templates as $template) { 890 $result[] = [ 891 'name' => $template['host'] 892 ]; 893 } 894 895 return $result; 896 } 897 898 /** 899 * Format triggers. 900 * 901 * @param array $triggers 902 * 903 * @return array 904 */ 905 protected function formatTriggers(array $triggers) { 906 $result = []; 907 908 CArrayHelper::sort($triggers, ['description', 'expression', 'recovery_expression']); 909 910 foreach ($triggers as $trigger) { 911 $data = [ 912 'expression' => $trigger['expression'], 913 'recovery_mode' => $trigger['recovery_mode'], 914 'recovery_expression' => $trigger['recovery_expression'], 915 'name' => $trigger['description'], 916 'event_name' => $trigger['event_name'], 917 'opdata' => $trigger['opdata'], 918 'correlation_mode' => $trigger['correlation_mode'], 919 'correlation_tag' => $trigger['correlation_tag'], 920 'url' => $trigger['url'], 921 'status' => $trigger['status'], 922 'priority' => $trigger['priority'], 923 'description' => $trigger['comments'], 924 'type' => $trigger['type'], 925 'manual_close' => $trigger['manual_close'], 926 'dependencies' => $this->formatDependencies($trigger['dependencies']), 927 'tags' => $this->formatTags($trigger['tags']) 928 ]; 929 930 if (array_key_exists('uuid', $trigger)) { 931 $data['uuid'] = $trigger['uuid']; 932 } 933 934 if ($trigger['flags'] == ZBX_FLAG_DISCOVERY_PROTOTYPE) { 935 $data['discover'] = $trigger['discover']; 936 } 937 938 $result[] = $data; 939 } 940 941 return $result; 942 } 943 944 /** 945 * Format host interfaces. 946 * 947 * @param array $interfaces 948 * 949 * @return array 950 */ 951 protected function formatHostInterfaces(array $interfaces) { 952 $result = []; 953 954 CArrayHelper::sort($interfaces, ['type', 'ip', 'dns', 'port']); 955 956 foreach ($interfaces as $interface) { 957 $result[] = [ 958 'default' => $interface['main'], 959 'type' => $interface['type'], 960 'useip' => $interface['useip'], 961 'ip' => $interface['ip'], 962 'dns' => $interface['dns'], 963 'port' => $interface['port'], 964 'details' => $interface['details'], 965 'interface_ref' => $interface['interface_ref'] 966 ]; 967 } 968 969 return $result; 970 } 971 972 /** 973 * Format host prototype interfaces. 974 * 975 * @param array $interfaces 976 * 977 * @return array 978 */ 979 protected function formatHostPrototypeInterfaces(array $interfaces): array { 980 $result = []; 981 982 CArrayHelper::sort($interfaces, ['type', 'ip', 'dns', 'port']); 983 984 foreach ($interfaces as $num => $interface) { 985 $result[$num] = [ 986 'default' => $interface['main'], 987 'type' => $interface['type'], 988 'useip' => $interface['useip'], 989 'ip' => $interface['ip'], 990 'dns' => $interface['dns'], 991 'port' => $interface['port'] 992 ]; 993 994 if ($interface['type'] == INTERFACE_TYPE_SNMP) { 995 $result[$num]['details'] = $interface['details']; 996 } 997 } 998 999 return $result; 1000 } 1001 1002 /** 1003 * Format groups. 1004 * 1005 * @param array $groups 1006 * 1007 * @return array 1008 */ 1009 protected function formatGroups(array $groups) { 1010 $result = []; 1011 1012 CArrayHelper::sort($groups, ['name']); 1013 1014 foreach ($groups as $group) { 1015 $result[] = [ 1016 'uuid' => $group['uuid'], 1017 'name' => $group['name'] 1018 ]; 1019 } 1020 1021 return $result; 1022 } 1023 1024 /** 1025 * Format items. 1026 * 1027 * @param array $items 1028 * @param array $simple_triggers 1029 * 1030 * @return array 1031 */ 1032 protected function formatItems(array $items, array $simple_triggers) { 1033 $result = []; 1034 1035 CArrayHelper::sort($items, ['key_']); 1036 1037 foreach ($items as $item) { 1038 $data = [ 1039 'uuid' => $item['uuid'], 1040 'name' => $item['name'], 1041 'type' => $item['type'], 1042 'snmp_oid' => $item['snmp_oid'], 1043 'key' => $item['key_'], 1044 'delay' => $item['delay'], 1045 'history' => $item['history'], 1046 'trends' => $item['trends'], 1047 'status' => $item['status'], 1048 'value_type' => $item['value_type'], 1049 'allowed_hosts' => $item['trapper_hosts'], 1050 'units' => $item['units'], 1051 'params' => $item['params'], 1052 'ipmi_sensor' => $item['ipmi_sensor'], 1053 'authtype' => $item['authtype'], 1054 'username' => $item['username'], 1055 'password' => $item['password'], 1056 'publickey' => $item['publickey'], 1057 'privatekey' => $item['privatekey'], 1058 'description' => $item['description'], 1059 'inventory_link' => $item['inventory_link'], 1060 'valuemap' => $item['valuemap'], 1061 'logtimefmt' => $item['logtimefmt'], 1062 'preprocessing' => self::formatPreprocessingSteps($item['preprocessing']), 1063 'jmx_endpoint' => $item['jmx_endpoint'], 1064 'timeout' => $item['timeout'], 1065 'url' => $item['url'], 1066 'query_fields' => $item['query_fields'], 1067 'parameters' => $item['parameters'], 1068 'posts' => $item['posts'], 1069 'status_codes' => $item['status_codes'], 1070 'follow_redirects' => $item['follow_redirects'], 1071 'post_type' => $item['post_type'], 1072 'http_proxy' => $item['http_proxy'], 1073 'headers' => $item['headers'], 1074 'retrieve_mode' => $item['retrieve_mode'], 1075 'request_method' => $item['request_method'], 1076 'output_format' => $item['output_format'], 1077 'allow_traps' => $item['allow_traps'], 1078 'ssl_cert_file' => $item['ssl_cert_file'], 1079 'ssl_key_file' => $item['ssl_key_file'], 1080 'ssl_key_password' => $item['ssl_key_password'], 1081 'tags' => $this->formatTags($item['tags']), 1082 'verify_peer' => $item['verify_peer'], 1083 'verify_host' => $item['verify_host'] 1084 ]; 1085 1086 $master_item = ($item['type'] == ITEM_TYPE_DEPENDENT) ? ['key' => $item['master_item']['key_']] : []; 1087 1088 if ($item['flags'] == ZBX_FLAG_DISCOVERY_PROTOTYPE) { 1089 $data['discover'] = $item['discover']; 1090 } 1091 1092 $data['master_item'] = $master_item; 1093 1094 if (isset($item['interface_ref'])) { 1095 $data['interface_ref'] = $item['interface_ref']; 1096 } 1097 1098 if ($item['query_fields']) { 1099 $query_fields = []; 1100 1101 foreach ($item['query_fields'] as $query_field) { 1102 $query_fields[] = [ 1103 'name' => key($query_field), 1104 'value' => reset($query_field) 1105 ]; 1106 } 1107 1108 $data['query_fields'] = $query_fields; 1109 } 1110 1111 if ($item['headers']) { 1112 $headers = []; 1113 1114 foreach ($item['headers'] as $name => $value) { 1115 $headers[] = compact('name', 'value'); 1116 } 1117 1118 $data['headers'] = $headers; 1119 } 1120 1121 if ($simple_triggers) { 1122 $triggers = []; 1123 foreach ($simple_triggers as $simple_trigger) { 1124 if (bccomp($item['itemid'], $simple_trigger['items'][0]['itemid']) == 0) { 1125 $triggers[] = $simple_trigger; 1126 } 1127 } 1128 1129 if ($triggers) { 1130 $key = array_key_exists('discoveryRule', $item) ? 'trigger_prototypes' : 'triggers'; 1131 $data[$key] = $this->formatTriggers($triggers); 1132 } 1133 } 1134 1135 $result[] = $data; 1136 } 1137 1138 return $result; 1139 } 1140 1141 /** 1142 * Format macros. 1143 * 1144 * @param array $macros 1145 * 1146 * @return array 1147 */ 1148 protected function formatMacros(array $macros) { 1149 $result = []; 1150 1151 $macros = order_macros($macros, 'macro'); 1152 1153 foreach ($macros as $macro) { 1154 $result[] = [ 1155 'macro' => $macro['macro'], 1156 'type' => $macro['type'], 1157 'value' => array_key_exists('value', $macro) ? $macro['value'] : '', 1158 'description' => $macro['description'] 1159 ]; 1160 } 1161 1162 return $result; 1163 } 1164 1165 /** 1166 * Format trigger dependencies. 1167 * 1168 * @param array $dependencies 1169 * 1170 * @return array 1171 */ 1172 protected function formatDependencies(array $dependencies) { 1173 $result = []; 1174 1175 CArrayHelper::sort($dependencies, ['description', 'expression', 'recovery_expression']); 1176 1177 foreach ($dependencies as $dependency) { 1178 $result[] = [ 1179 'name' => $dependency['description'], 1180 'expression' => $dependency['expression'], 1181 'recovery_expression' => $dependency['recovery_expression'] 1182 ]; 1183 } 1184 1185 return $result; 1186 } 1187 1188 /** 1189 * Format tags. 1190 * 1191 * @param array $tags 1192 * 1193 * @return array 1194 */ 1195 protected function formatTags(array $tags) { 1196 $result = []; 1197 $fields = [ 1198 'tag' => true, 1199 'value' => true, 1200 'operator' => true 1201 ]; 1202 1203 CArrayHelper::sort($tags, ['tag', 'value']); 1204 1205 foreach ($tags as $tag) { 1206 $result[] = array_intersect_key($tag, $fields); 1207 } 1208 1209 return $result; 1210 } 1211 1212 /** 1213 * Format dashboards. 1214 * 1215 * @param array $dashboards 1216 * 1217 * @return array 1218 */ 1219 protected function formatDashboards(array $dashboards) { 1220 $result = []; 1221 1222 CArrayHelper::sort($dashboards, ['name']); 1223 1224 foreach ($dashboards as $dashboard) { 1225 $result[] = [ 1226 'uuid' => $dashboard['uuid'], 1227 'name' => $dashboard['name'], 1228 'display_period' => $dashboard['display_period'], 1229 'auto_start' => $dashboard['auto_start'], 1230 'pages' => $this->formatDashboardPages($dashboard['pages']) 1231 ]; 1232 } 1233 1234 return $result; 1235 } 1236 1237 /** 1238 * Format dashboard pages. 1239 * 1240 * @param array $dashboard_pages 1241 * 1242 * @return array 1243 */ 1244 protected function formatDashboardPages(array $dashboard_pages) { 1245 $result = []; 1246 1247 foreach ($dashboard_pages as $dashboard_page) { 1248 $result[] = [ 1249 'name' => $dashboard_page['name'], 1250 'display_period' => $dashboard_page['display_period'], 1251 'widgets' => $this->formatWidgets($dashboard_page['widgets']) 1252 ]; 1253 } 1254 1255 return $result; 1256 } 1257 1258 /** 1259 * Format widgets. 1260 * 1261 * @param array $widgets 1262 * 1263 * @return array 1264 */ 1265 protected function formatWidgets(array $widgets) { 1266 $result = []; 1267 1268 CArrayHelper::sort($widgets, ['name']); 1269 1270 foreach ($widgets as $widget) { 1271 $result[] = [ 1272 'type' => $widget['type'], 1273 'name' => $widget['name'], 1274 'x' => $widget['x'], 1275 'y' => $widget['y'], 1276 'width' => $widget['width'], 1277 'height' => $widget['height'], 1278 'hide_header' => $widget['view_mode'], 1279 'fields' => $this->formatWidgetFields($widget['fields']) 1280 ]; 1281 } 1282 1283 return $result; 1284 } 1285 1286 /** 1287 * Format widget fields. 1288 * 1289 * @param array $widgets 1290 * 1291 * @return array 1292 */ 1293 protected function formatWidgetFields(array $fields) { 1294 $result = []; 1295 1296 CArrayHelper::sort($fields, ['type']); 1297 1298 foreach ($fields as $field) { 1299 $result[] = [ 1300 'type' => $field['type'], 1301 'name' => $field['name'], 1302 'value' => $field['value'] 1303 ]; 1304 } 1305 1306 return $result; 1307 } 1308 1309 /** 1310 * Format graph items. 1311 * 1312 * @param array $graphItems 1313 * 1314 * @return array 1315 */ 1316 protected function formatGraphItems(array $graphItems) { 1317 $result = []; 1318 1319 CArrayHelper::sort($graphItems, ['sortorder']); 1320 1321 foreach ($graphItems as $graphItem) { 1322 $result[] = [ 1323 'sortorder'=> $graphItem['sortorder'], 1324 'drawtype'=> $graphItem['drawtype'], 1325 'color'=> $graphItem['color'], 1326 'yaxisside'=> $graphItem['yaxisside'], 1327 'calc_fnc'=> $graphItem['calc_fnc'], 1328 'type'=> $graphItem['type'], 1329 'item'=> $graphItem['itemid'] 1330 ]; 1331 } 1332 1333 return $result; 1334 } 1335 1336 /** 1337 * Format map urls. 1338 * 1339 * @param array $urls 1340 * 1341 * @return array 1342 */ 1343 protected function formatMapUrls(array $urls) { 1344 $result = []; 1345 1346 CArrayHelper::sort($urls, ['name', 'url']); 1347 1348 foreach ($urls as $url) { 1349 $result[] = [ 1350 'name' => $url['name'], 1351 'url' => $url['url'], 1352 'elementtype' => $url['elementtype'] 1353 ]; 1354 } 1355 1356 return $result; 1357 } 1358 1359 /** 1360 * Format map element urls. 1361 * 1362 * @param array $urls 1363 * 1364 * @return array 1365 */ 1366 protected function formatMapElementUrls(array $urls) { 1367 $result = []; 1368 1369 CArrayHelper::sort($urls, ['name', 'url']); 1370 1371 foreach ($urls as $url) { 1372 $result[] = [ 1373 'name' => $url['name'], 1374 'url' => $url['url'] 1375 ]; 1376 } 1377 1378 return $result; 1379 } 1380 1381 /** 1382 * Format map links. 1383 * 1384 * @param array $links Map links 1385 * @param array $selements Map elements 1386 * 1387 * @return array 1388 */ 1389 protected function formatMapLinks(array $links, array $selements) { 1390 $result = []; 1391 1392 // Get array where key is selementid and value is sort position. 1393 $flipped_selements = []; 1394 $selements = array_values($selements); 1395 1396 foreach ($selements as $key => $item) { 1397 if (array_key_exists('selementid', $item)) { 1398 $flipped_selements[$item['selementid']] = $key; 1399 } 1400 } 1401 1402 foreach ($links as &$link) { 1403 $link['selementpos1'] = $flipped_selements[$link['selementid1']]; 1404 $link['selementpos2'] = $flipped_selements[$link['selementid2']]; 1405 1406 // Sort selements by position asc. 1407 if ($link['selementpos2'] < $link['selementpos1']) { 1408 [$link['selementpos1'], $link['selementpos2']] = [$link['selementpos2'], $link['selementpos1']]; 1409 } 1410 } 1411 unset($link); 1412 1413 CArrayHelper::sort($links, ['selementpos1', 'selementpos2']); 1414 1415 foreach ($links as $link) { 1416 $result[] = [ 1417 'drawtype' => $link['drawtype'], 1418 'color' => $link['color'], 1419 'label' => $link['label'], 1420 'selementid1' => $link['selementid1'], 1421 'selementid2' => $link['selementid2'], 1422 'linktriggers' => $this->formatMapLinkTriggers($link['linktriggers']) 1423 ]; 1424 } 1425 1426 return $result; 1427 } 1428 1429 /** 1430 * Format map link triggers. 1431 * 1432 * @param array $linktriggers 1433 * 1434 * @return array 1435 */ 1436 protected function formatMapLinkTriggers(array $linktriggers) { 1437 $result = []; 1438 1439 foreach ($linktriggers as &$linktrigger) { 1440 $linktrigger['description'] = $linktrigger['triggerid']['description']; 1441 $linktrigger['expression'] = $linktrigger['triggerid']['expression']; 1442 $linktrigger['recovery_expression'] = $linktrigger['triggerid']['recovery_expression']; 1443 } 1444 unset($linktrigger); 1445 1446 CArrayHelper::sort($linktriggers, ['description', 'expression', 'recovery_expression']); 1447 1448 foreach ($linktriggers as $linktrigger) { 1449 $result[] = [ 1450 'drawtype' => $linktrigger['drawtype'], 1451 'color' => $linktrigger['color'], 1452 'trigger' => $linktrigger['triggerid'] 1453 ]; 1454 } 1455 1456 return $result; 1457 } 1458 1459 /** 1460 * Format map elements. 1461 * 1462 * @param array $elements 1463 * 1464 * @return array 1465 */ 1466 protected function formatMapElements(array $elements) { 1467 $result = []; 1468 1469 CArrayHelper::sort($elements, ['y', 'x']); 1470 1471 foreach ($elements as $element) { 1472 $result[] = [ 1473 'elementtype' => $element['elementtype'], 1474 'label' => $element['label'], 1475 'label_location' => $element['label_location'], 1476 'x' => $element['x'], 1477 'y' => $element['y'], 1478 'elementsubtype' => $element['elementsubtype'], 1479 'areatype' => $element['areatype'], 1480 'width' => $element['width'], 1481 'height' => $element['height'], 1482 'viewtype' => $element['viewtype'], 1483 'use_iconmap' => $element['use_iconmap'], 1484 'selementid' => $element['selementid'], 1485 'elements' => $element['elements'], 1486 'icon_off' => $element['iconid_off'], 1487 'icon_on' => $element['iconid_on'], 1488 'icon_disabled' => $element['iconid_disabled'], 1489 'icon_maintenance' => $element['iconid_maintenance'], 1490 'urls' => $this->formatMapElementUrls($element['urls']), 1491 'evaltype' => $element['evaltype'], 1492 'tags' => $this->formatTags($element['tags']) 1493 ]; 1494 } 1495 1496 return $result; 1497 } 1498} 1499