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 * Class containing methods for operations with maintenances. 24 * 25 * * @package API 26 */ 27class CMaintenance extends CApiService { 28 29 protected $tableName = 'maintenances'; 30 protected $tableAlias = 'm'; 31 protected $sortColumns = ['maintenanceid', 'name', 'maintenance_type', 'active_till', 'active_since']; 32 33 /** 34 * Get maintenances data. 35 * 36 * @param array $options 37 * @param array $options['itemids'] 38 * @param array $options['hostids'] 39 * @param array $options['groupids'] 40 * @param array $options['triggerids'] 41 * @param array $options['maintenanceids'] 42 * @param bool $options['status'] 43 * @param bool $options['editable'] 44 * @param bool $options['count'] 45 * @param string $options['pattern'] 46 * @param int $options['limit'] 47 * @param string $options['order'] 48 * 49 * @return array 50 */ 51 public function get(array $options = []) { 52 $result = []; 53 54 $sqlParts = [ 55 'select' => ['maintenance' => 'm.maintenanceid'], 56 'from' => ['maintenances' => 'maintenances m'], 57 'where' => [], 58 'group' => [], 59 'order' => [], 60 'limit' => null 61 ]; 62 63 $defOptions = [ 64 'groupids' => null, 65 'hostids' => null, 66 'maintenanceids' => null, 67 'editable' => false, 68 'nopermissions' => null, 69 // filter 70 'filter' => null, 71 'search' => null, 72 'searchByAny' => null, 73 'startSearch' => null, 74 'excludeSearch' => null, 75 'filter' => null, 76 'searchWildcardsEnabled' => null, 77 // output 78 'output' => API_OUTPUT_EXTEND, 79 'selectGroups' => null, 80 'selectHosts' => null, 81 'selectTimeperiods' => null, 82 'countOutput' => null, 83 'groupCount' => null, 84 'preservekeys' => null, 85 'sortfield' => '', 86 'sortorder' => '', 87 'limit' => null 88 ]; 89 $options = zbx_array_merge($defOptions, $options); 90 91 // editable + PERMISSION CHECK 92 $maintenanceids = []; 93 if (self::$userData['type'] == USER_TYPE_SUPER_ADMIN || $options['nopermissions']) { 94 if (!is_null($options['groupids']) || !is_null($options['hostids'])) { 95 if (!is_null($options['groupids'])) { 96 zbx_value2array($options['groupids']); 97 $res = DBselect( 98 'SELECT mmg.maintenanceid'. 99 ' FROM maintenances_groups mmg'. 100 ' WHERE '.dbConditionInt('mmg.groupid', $options['groupids']) 101 ); 102 while ($maintenance = DBfetch($res)) { 103 $maintenanceids[] = $maintenance['maintenanceid']; 104 } 105 } 106 107 $sql = 'SELECT mmh.maintenanceid'. 108 ' FROM maintenances_hosts mmh,hosts_groups hg'. 109 ' WHERE hg.hostid=mmh.hostid'; 110 111 if (!is_null($options['groupids'])) { 112 zbx_value2array($options['groupids']); 113 $sql .= ' AND '.dbConditionInt('hg.groupid', $options['groupids']); 114 } 115 116 if (!is_null($options['hostids'])) { 117 zbx_value2array($options['hostids']); 118 $sql .= ' AND '.dbConditionInt('hg.hostid', $options['hostids']); 119 } 120 $res = DBselect($sql); 121 while ($maintenance = DBfetch($res)) { 122 $maintenanceids[] = $maintenance['maintenanceid']; 123 } 124 $sqlParts['where'][] = dbConditionInt('m.maintenanceid', $maintenanceids); 125 } 126 } 127 else { 128 $permission = $options['editable'] ? PERM_READ_WRITE : PERM_READ; 129 $userGroups = getUserGroupsByUserId(self::$userData['userid']); 130 131 $sql = 'SELECT m.maintenanceid'. 132 ' FROM maintenances m'. 133 ' WHERE NOT EXISTS ('. 134 'SELECT NULL'. 135 ' FROM maintenances_hosts mh,hosts_groups hg'. 136 ' LEFT JOIN rights r'. 137 ' ON r.id=hg.groupid'. 138 ' AND '.dbConditionInt('r.groupid', $userGroups). 139 ' WHERE m.maintenanceid=mh.maintenanceid'. 140 ' AND mh.hostid=hg.hostid'. 141 ' GROUP by mh.hostid'. 142 ' HAVING MIN(r.permission) IS NULL'. 143 ' OR MIN(r.permission)='.PERM_DENY. 144 ' OR MAX(r.permission)<'.zbx_dbstr($permission). 145 ')'. 146 ' AND NOT EXISTS ('. 147 'SELECT NULL'. 148 ' FROM maintenances_groups mg'. 149 ' LEFT JOIN rights r'. 150 ' ON r.id=mg.groupid'. 151 ' AND '.dbConditionInt('r.groupid', $userGroups). 152 ' WHERE m.maintenanceid=mg.maintenanceid'. 153 ' GROUP by mg.groupid'. 154 ' HAVING MIN(r.permission) IS NULL'. 155 ' OR MIN(r.permission)='.PERM_DENY. 156 ' OR MAX(r.permission)<'.zbx_dbstr($permission). 157 ')'; 158 159 if (!is_null($options['groupids'])) { 160 zbx_value2array($options['groupids']); 161 $sql .= ' AND ('. 162 'EXISTS ('. 163 'SELECT NULL'. 164 ' FROM maintenances_groups mg'. 165 ' WHERE m.maintenanceid=mg.maintenanceid'. 166 ' AND '.dbConditionInt('mg.groupid', $options['groupids']). 167 ')'. 168 ' OR EXISTS ('. 169 'SELECT NULL'. 170 ' FROM maintenances_hosts mh,hosts_groups hg'. 171 ' WHERE m.maintenanceid=mh.maintenanceid'. 172 ' AND mh.hostid=hg.hostid'. 173 ' AND '.dbConditionInt('hg.groupid', $options['groupids']). 174 ')'. 175 ')'; 176 } 177 178 if (!is_null($options['hostids'])) { 179 zbx_value2array($options['hostids']); 180 $sql .= ' AND EXISTS ('. 181 'SELECT NULL'. 182 ' FROM maintenances_hosts mh'. 183 ' WHERE m.maintenanceid=mh.maintenanceid'. 184 ' AND '.dbConditionInt('mh.hostid', $options['hostids']). 185 ')'; 186 } 187 188 if (!is_null($options['maintenanceids'])) { 189 zbx_value2array($options['maintenanceids']); 190 $sql .= ' AND '.dbConditionInt('m.maintenanceid', $options['maintenanceids']); 191 } 192 193 $res = DBselect($sql); 194 while ($maintenance = DBfetch($res)) { 195 $maintenanceids[] = $maintenance['maintenanceid']; 196 } 197 $sqlParts['where'][] = dbConditionInt('m.maintenanceid', $maintenanceids); 198 } 199 200 // maintenanceids 201 if (!is_null($options['maintenanceids'])) { 202 zbx_value2array($options['maintenanceids']); 203 204 $sqlParts['where'][] = dbConditionInt('m.maintenanceid', $options['maintenanceids']); 205 } 206 207 // filter 208 if (is_array($options['filter'])) { 209 $this->dbFilter('maintenances m', $options, $sqlParts); 210 } 211 212 // search 213 if (is_array($options['search'])) { 214 zbx_db_search('maintenances m', $options, $sqlParts); 215 } 216 217 // limit 218 if (zbx_ctype_digit($options['limit']) && $options['limit']) { 219 $sqlParts['limit'] = $options['limit']; 220 } 221 222 $sqlParts = $this->applyQueryOutputOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts); 223 $sqlParts = $this->applyQuerySortOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts); 224 $res = DBselect($this->createSelectQueryFromParts($sqlParts), $sqlParts['limit']); 225 while ($maintenance = DBfetch($res)) { 226 if (!is_null($options['countOutput'])) { 227 if (!is_null($options['groupCount'])) { 228 $result[] = $maintenance; 229 } 230 else { 231 $result = $maintenance['rowscount']; 232 } 233 } 234 else { 235 $result[$maintenance['maintenanceid']] = $maintenance; 236 } 237 } 238 239 if (!is_null($options['countOutput'])) { 240 return $result; 241 } 242 243 if ($result) { 244 $result = $this->addRelatedObjects($options, $result); 245 } 246 247 if (is_null($options['preservekeys'])) { 248 $result = zbx_cleanHashes($result); 249 } 250 return $result; 251 } 252 253 /** 254 * Add maintenances. 255 * 256 * @param array $maintenances 257 * 258 * @return boolean 259 */ 260 public function create(array $maintenances) { 261 $maintenances = zbx_toArray($maintenances); 262 if (self::$userData['type'] == USER_TYPE_ZABBIX_USER) { 263 self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); 264 } 265 266 $hostids = []; 267 $groupids = []; 268 foreach ($maintenances as $maintenance) { 269 $hostids = array_merge($hostids, $maintenance['hostids']); 270 $groupids = array_merge($groupids, $maintenance['groupids']); 271 } 272 273 // validate hosts & groups 274 if (empty($hostids) && empty($groupids)) { 275 self::exception(ZBX_API_ERROR_PARAMETERS, _('At least one host or group should be selected.')); 276 } 277 278 // hosts permissions 279 $options = [ 280 'hostids' => $hostids, 281 'editable' => true, 282 'output' => ['hostid'], 283 'preservekeys' => true 284 ]; 285 $updHosts = API::Host()->get($options); 286 foreach ($hostids as $hostid) { 287 if (!isset($updHosts[$hostid])) { 288 self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); 289 } 290 } 291 // groups permissions 292 $options = [ 293 'groupids' => $groupids, 294 'editable' => true, 295 'output' => ['groupid'], 296 'preservekeys' => true 297 ]; 298 $updGroups = API::HostGroup()->get($options); 299 foreach ($groupids as $groupid) { 300 if (!isset($updGroups[$groupid])) { 301 self::exception(ZBX_API_ERROR_PERMISSIONS, _('No permissions to referred object or it does not exist!')); 302 } 303 } 304 305 $this->removeSecondsFromTimes($maintenances); 306 307 $tid = 0; 308 $insert = []; 309 $timeperiods = []; 310 $insertTimeperiods = []; 311 $now = time(); 312 $now -= $now % SEC_PER_MIN; 313 314 // check fields 315 foreach ($maintenances as $maintenance) { 316 $dbFields = [ 317 'name' => null, 318 'active_since' => null, 319 'active_till' => null 320 ]; 321 322 if (!check_db_fields($dbFields, $maintenance)) { 323 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect parameters for maintenance.')); 324 } 325 } 326 327 $collectionValidator = new CCollectionValidator([ 328 'uniqueField' => 'name', 329 'messageDuplicate' => _('Maintenance "%1$s" already exists.') 330 ]); 331 $this->checkValidator($maintenances, $collectionValidator); 332 333 // validate if maintenance name already exists 334 $dbMaintenances = $this->get([ 335 'output' => ['name'], 336 'filter' => ['name' => zbx_objectValues($maintenances, 'name')], 337 'nopermissions' => true, 338 'limit' => 1 339 ]); 340 341 if ($dbMaintenances) { 342 $dbMaintenance = reset($dbMaintenances); 343 self::exception(ZBX_API_ERROR_PARAMETERS, _s('Maintenance "%1$s" already exists.', $dbMaintenance['name'])); 344 } 345 346 foreach ($maintenances as $mnum => $maintenance) { 347 // validate maintenance active since 348 if (!validateUnixTime($maintenance['active_since'])) { 349 self::exception(ZBX_API_ERROR_PARAMETERS, _s('"%s" must be between 1970.01.01 and 2038.01.18.', _('Active since'))); 350 } 351 352 // validate maintenance active till 353 if (!validateUnixTime($maintenance['active_till'])) { 354 self::exception(ZBX_API_ERROR_PARAMETERS, _s('"%s" must be between 1970.01.01 and 2038.01.18.', _('Active till'))); 355 } 356 357 // validate maintenance active interval 358 if ($maintenance['active_since'] > $maintenance['active_till']) { 359 self::exception(ZBX_API_ERROR_PARAMETERS, _('Maintenance "Active since" value cannot be bigger than "Active till".')); 360 } 361 362 // validate timeperiods 363 if (!array_key_exists('timeperiods', $maintenance) || !is_array($maintenance['timeperiods']) 364 || !$maintenance['timeperiods']) { 365 self::exception(ZBX_API_ERROR_PARAMETERS, _('At least one maintenance period must be created.')); 366 } 367 368 foreach ($maintenance['timeperiods'] as $timeperiod) { 369 if (!is_array($timeperiod)) { 370 self::exception(ZBX_API_ERROR_PARAMETERS, _('At least one maintenance period must be created.')); 371 } 372 373 $dbFields = [ 374 'timeperiod_type' => TIMEPERIOD_TYPE_ONETIME, 375 'period' => SEC_PER_HOUR, 376 'start_date' => $now 377 ]; 378 check_db_fields($dbFields, $timeperiod); 379 380 $tid++; 381 $insertTimeperiods[$tid] = $timeperiod; 382 $timeperiods[$tid] = $mnum; 383 } 384 385 $insert[$mnum] = $maintenance; 386 } 387 $maintenanceids = DB::insert('maintenances', $insert); 388 $timeperiodids = DB::insert('timeperiods', $insertTimeperiods); 389 390 $insertWindows = []; 391 foreach ($timeperiods as $tid => $mnum) { 392 $insertWindows[] = [ 393 'timeperiodid' => $timeperiodids[$tid], 394 'maintenanceid' => $maintenanceids[$mnum] 395 ]; 396 } 397 DB::insert('maintenances_windows', $insertWindows); 398 399 $insertHosts = []; 400 $insertGroups = []; 401 foreach ($maintenances as $mnum => $maintenance) { 402 foreach ($maintenance['hostids'] as $hostid) { 403 $insertHosts[] = [ 404 'hostid' => $hostid, 405 'maintenanceid' => $maintenanceids[$mnum] 406 ]; 407 } 408 foreach ($maintenance['groupids'] as $groupid) { 409 $insertGroups[] = [ 410 'groupid' => $groupid, 411 'maintenanceid' => $maintenanceids[$mnum] 412 ]; 413 } 414 415 add_audit_details(AUDIT_ACTION_ADD, AUDIT_RESOURCE_MAINTENANCE, $maintenanceids[$mnum], 416 $maintenance['name'], null 417 ); 418 } 419 DB::insert('maintenances_hosts', $insertHosts); 420 DB::insert('maintenances_groups', $insertGroups); 421 422 return ['maintenanceids' => $maintenanceids]; 423 } 424 425 /** 426 * Update maintenances. 427 * 428 * @param array $maintenances 429 * 430 * @throws APIException if no permissions to object, it does no exists or validation errors 431 * 432 * @return array 433 */ 434 public function update(array $maintenances) { 435 if (self::$userData['type'] == USER_TYPE_ZABBIX_USER) { 436 self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); 437 } 438 439 $maintenances = zbx_toArray($maintenances); 440 $maintenanceids = zbx_objectValues($maintenances, 'maintenanceid'); 441 442 if (!$maintenances) { 443 self::exception(ZBX_API_ERROR_PARAMETERS, _('Empty input parameter.')); 444 } 445 446 $db_fields = [ 447 'maintenanceid' => null 448 ]; 449 450 foreach ($maintenances as $maintenance) { 451 // Validate fields. 452 if (!check_db_fields($db_fields, $maintenance)) { 453 self::exception(ZBX_API_ERROR_PARAMETERS, _('Incorrect parameters for maintenance.')); 454 } 455 } 456 457 $db_maintenances = $this->get([ 458 'output' => API_OUTPUT_EXTEND, 459 'maintenanceids' => $maintenanceids, 460 'selectGroups' => ['groupid'], 461 'selectHosts' => ['hostid'], 462 'selectTimeperiods' => API_OUTPUT_EXTEND, 463 'editable' => true, 464 'preservekeys' => true 465 ]); 466 467 $changed_names = []; 468 $hostids = []; 469 $groupids = []; 470 471 foreach ($maintenances as $maintenance) { 472 if (!array_key_exists($maintenance['maintenanceid'], $db_maintenances)) { 473 self::exception(ZBX_API_ERROR_PERMISSIONS, 474 _('No permissions to referred object or it does not exist!') 475 ); 476 } 477 478 // Check maintenances names and collect for unique checking. 479 if (array_key_exists('name', $maintenance) && $maintenance['name'] !== '' 480 && $db_maintenances[$maintenance['maintenanceid']]['name'] !== $maintenance['name']) { 481 if (array_key_exists($maintenance['name'], $changed_names)) { 482 self::exception(ZBX_API_ERROR_PARAMETERS, 483 _s('Maintenance "%1$s" already exists.', $maintenance['name']) 484 ); 485 } 486 487 $changed_names[$maintenance['name']] = $maintenance['name']; 488 } 489 490 // Validate maintenance active since. 491 if (array_key_exists('active_since', $maintenance)) { 492 $active_since = $maintenance['active_since']; 493 494 if (!validateUnixTime($active_since)) { 495 self::exception(ZBX_API_ERROR_PARAMETERS, 496 _s('"%s" must be between 1970.01.01 and 2038.01.18.', _('Active since')) 497 ); 498 } 499 } 500 else { 501 $active_since = $db_maintenances[$maintenance['maintenanceid']]['active_since']; 502 } 503 504 // Validate maintenance active till. 505 if (array_key_exists('active_till', $maintenance)) { 506 $active_till = $maintenance['active_till']; 507 508 if (!validateUnixTime($active_till)) { 509 self::exception(ZBX_API_ERROR_PARAMETERS, 510 _s('"%s" must be between 1970.01.01 and 2038.01.18.', _('Active till')) 511 ); 512 } 513 } 514 else { 515 $active_till = $db_maintenances[$maintenance['maintenanceid']]['active_till']; 516 } 517 518 // Validate maintenance active interval. 519 if ($active_since > $active_till) { 520 self::exception(ZBX_API_ERROR_PARAMETERS, 521 _('Maintenance "Active since" value cannot be bigger than "Active till".') 522 ); 523 } 524 525 // Validate timeperiods. 526 if (array_key_exists('timeperiods', $maintenance)) { 527 if (!is_array($maintenance['timeperiods']) || !$maintenance['timeperiods']) { 528 self::exception(ZBX_API_ERROR_PARAMETERS, _('At least one maintenance period must be created.')); 529 } 530 531 foreach ($maintenance['timeperiods'] as $timeperiod) { 532 if (!is_array($timeperiod)) { 533 self::exception(ZBX_API_ERROR_PARAMETERS, 534 _('At least one maintenance period must be created.') 535 ); 536 } 537 } 538 } 539 540 // Collect hostids for permission checking. 541 if (array_key_exists('hostids', $maintenance) && is_array($maintenance['hostids'])) { 542 $hostids = array_merge($hostids, $maintenance['hostids']); 543 $has_hosts = (bool) $maintenance['hostids']; 544 } 545 else { 546 $has_hosts = (bool) $db_maintenances[$maintenance['maintenanceid']]['hosts']; 547 } 548 549 // Collect groupids for permission checking. 550 if (array_key_exists('groupids', $maintenance) && is_array($maintenance['groupids'])) { 551 $groupids = array_merge($groupids, $maintenance['groupids']); 552 $has_groups = (bool) $maintenance['groupids']; 553 } 554 else { 555 $has_groups = (bool) $db_maintenances[$maintenance['maintenanceid']]['groups']; 556 } 557 558 if (!$has_hosts && !$has_groups) { 559 self::exception(ZBX_API_ERROR_PARAMETERS, _('At least one host or group should be selected.')); 560 } 561 } 562 563 // Check if maintenance already exists. 564 if ($changed_names) { 565 $db_maintenances_names = $this->get([ 566 'output' => ['name'], 567 'filter' => ['name' => $changed_names], 568 'nopermissions' => true, 569 'limit' => 1 570 ]); 571 572 if ($db_maintenances_names) { 573 $maintenance = reset($db_maintenances_names); 574 self::exception(ZBX_API_ERROR_PARAMETERS, 575 _s('Maintenance "%1$s" already exists.', $maintenance['name']) 576 ); 577 } 578 } 579 580 // Check hosts permission and availability. 581 if ($hostids) { 582 $db_hosts = API::Host()->get([ 583 'output' => [], 584 'hostids' => $hostids, 585 'editable' => true, 586 'preservekeys' => true 587 ]); 588 589 foreach ($hostids as $hostid) { 590 if (!array_key_exists($hostid, $db_hosts)) { 591 self::exception(ZBX_API_ERROR_PERMISSIONS, 592 _('No permissions to referred object or it does not exist!') 593 ); 594 } 595 } 596 } 597 598 // Check host groups permission and availability. 599 if ($groupids) { 600 $db_groups = API::HostGroup()->get([ 601 'output' => [], 602 'groupids' => $groupids, 603 'editable' => true, 604 'preservekeys' => true 605 ]); 606 607 foreach ($groupids as $groupid) { 608 if (!array_key_exists($groupid, $db_groups)) { 609 self::exception(ZBX_API_ERROR_PERMISSIONS, 610 _('No permissions to referred object or it does not exist!') 611 ); 612 } 613 } 614 } 615 616 $this->removeSecondsFromTimes($maintenances); 617 618 $update_maintenances = []; 619 foreach ($maintenances as $mnum => $maintenance) { 620 $update_maintenances[$mnum] = [ 621 'values' => $maintenance, 622 'where' => ['maintenanceid' => $maintenance['maintenanceid']] 623 ]; 624 625 // Update time periods. 626 if (array_key_exists('timeperiods', $maintenance)) { 627 $this->replaceTimePeriods($db_maintenances[$maintenance['maintenanceid']], $maintenance); 628 } 629 630 add_audit_ext( 631 AUDIT_ACTION_UPDATE, 632 AUDIT_RESOURCE_MAINTENANCE, 633 $maintenance['maintenanceid'], 634 array_key_exists('name', $maintenance) 635 ? $maintenance['name'] 636 : $db_maintenances[$maintenance['maintenanceid']]['name'], 637 'maintenances', 638 $db_maintenances[$maintenance['maintenanceid']], 639 $maintenance 640 ); 641 } 642 DB::update('maintenances', $update_maintenances); 643 644 // Some of the hosts and groups bound to maintenance must be deleted, other inserted and others left alone. 645 $insert_hosts = []; 646 $insert_groups = []; 647 648 foreach ($maintenances as $maintenance) { 649 if (array_key_exists('hostids', $maintenance)) { 650 // Putting apart those host<->maintenance connections that should be inserted, deleted and not changed: 651 // $hosts_diff['first'] - new hosts, that should be inserted; 652 // $hosts_diff['second'] - hosts, that should be deleted; 653 // $hosts_diff['both'] - hosts, that should not be touched; 654 $hosts_diff = zbx_array_diff( 655 zbx_toObject($maintenance['hostids'], 'hostid'), 656 $db_maintenances[$maintenance['maintenanceid']]['hosts'], 657 'hostid' 658 ); 659 660 foreach ($hosts_diff['first'] as $host) { 661 $insert_hosts[] = [ 662 'hostid' => $host['hostid'], 663 'maintenanceid' => $maintenance['maintenanceid'] 664 ]; 665 } 666 foreach ($hosts_diff['second'] as $host) { 667 DB::delete('maintenances_hosts', [ 668 'hostid' => $host['hostid'], 669 'maintenanceid' => $maintenance['maintenanceid'] 670 ]); 671 } 672 } 673 674 if (array_key_exists('groupids', $maintenance)) { 675 // Now the same with the groups. 676 $groups_diff = zbx_array_diff( 677 zbx_toObject($maintenance['groupids'], 'groupid'), 678 $db_maintenances[$maintenance['maintenanceid']]['groups'], 679 'groupid' 680 ); 681 682 foreach ($groups_diff['first'] as $group) { 683 $insert_groups[] = [ 684 'groupid' => $group['groupid'], 685 'maintenanceid' => $maintenance['maintenanceid'] 686 ]; 687 } 688 foreach ($groups_diff['second'] as $group) { 689 DB::delete('maintenances_groups', [ 690 'groupid' => $group['groupid'], 691 'maintenanceid' => $maintenance['maintenanceid'] 692 ]); 693 } 694 } 695 } 696 697 if ($insert_hosts) { 698 DB::insert('maintenances_hosts', $insert_hosts); 699 } 700 701 if ($insert_groups) { 702 DB::insert('maintenances_groups', $insert_groups); 703 } 704 705 return ['maintenanceids' => $maintenanceids]; 706 } 707 708 /** 709 * Delete Maintenances. 710 * 711 * @param array $maintenanceids 712 * 713 * @return array 714 */ 715 public function delete(array $maintenanceids) { 716 if (self::$userData['type'] == USER_TYPE_ZABBIX_USER) { 717 self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); 718 } 719 720 $options = [ 721 'output' => ['maintenanceid', 'name'], 722 'maintenanceids' => $maintenanceids, 723 'editable' => true, 724 'preservekeys' => true 725 ]; 726 $maintenances = $this->get($options); 727 foreach ($maintenanceids as $maintenanceid) { 728 if (!isset($maintenances[$maintenanceid])) { 729 self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.')); 730 } 731 } 732 733 $timeperiodids = []; 734 $dbTimeperiods = DBselect( 735 'SELECT DISTINCT tp.timeperiodid'. 736 ' FROM timeperiods tp,maintenances_windows mw'. 737 ' WHERE '.dbConditionInt('mw.maintenanceid', $maintenanceids). 738 ' AND tp.timeperiodid=mw.timeperiodid' 739 ); 740 while ($timeperiod = DBfetch($dbTimeperiods)) { 741 $timeperiodids[] = $timeperiod['timeperiodid']; 742 } 743 744 $midCond = ['maintenanceid' => $maintenanceids]; 745 746 // remove maintenanceid from hosts table 747 $options = [ 748 'real_hosts' => true, 749 'output' => ['hostid'], 750 'filter' => ['maintenanceid' => $maintenanceids] 751 ]; 752 $hosts = API::Host()->get($options); 753 if (!empty($hosts)) { 754 DB::update('hosts', [ 755 'values' => ['maintenanceid' => 0], 756 'where' => ['hostid' => zbx_objectValues($hosts, 'hostid')] 757 ]); 758 } 759 760 DB::delete('timeperiods', ['timeperiodid' => $timeperiodids]); 761 DB::delete('maintenances_windows', $midCond); 762 DB::delete('maintenances_hosts', $midCond); 763 DB::delete('maintenances_groups', $midCond); 764 DB::delete('maintenances', $midCond); 765 766 foreach ($maintenances as $maintenanceid => $maintenance) { 767 add_audit_details(AUDIT_ACTION_DELETE, AUDIT_RESOURCE_MAINTENANCE, $maintenanceid, $maintenance['name'], 768 null 769 ); 770 } 771 772 return ['maintenanceids' => $maintenanceids]; 773 } 774 775 /** 776 * Reset seconds to zero in maintenace time values. 777 * 778 * @param array $maintenances passed by reference 779 */ 780 protected function removeSecondsFromTimes(array &$maintenances) { 781 foreach ($maintenances as &$maintenance) { 782 if (isset($maintenance['active_since'])) { 783 $maintenance['active_since'] -= $maintenance['active_since'] % SEC_PER_MIN; 784 } 785 786 if (isset($maintenance['active_till'])) { 787 $maintenance['active_till'] -= $maintenance['active_till'] % SEC_PER_MIN; 788 } 789 790 791 if (isset($maintenance['timeperiods'])) { 792 foreach ($maintenance['timeperiods'] as &$timeperiod) { 793 if (isset($timeperiod['start_date'])) { 794 $timeperiod['start_date'] -= $timeperiod['start_date'] % SEC_PER_MIN; 795 } 796 } 797 unset($timeperiod); 798 } 799 } 800 unset($maintenance); 801 } 802 803 /** 804 * Updates maintenance time periods. 805 * 806 * @param array $maintenance 807 * @param array $oldMaintenance 808 */ 809 protected function replaceTimePeriods(array $oldMaintenance, array $maintenance) { 810 // replace time periods 811 $timePeriods = DB::replace('timeperiods', $oldMaintenance['timeperiods'], $maintenance['timeperiods']); 812 813 // link new time periods to maintenance 814 $oldTimePeriods = zbx_toHash($oldMaintenance['timeperiods'], 'timeperiodid'); 815 $newMaintenanceWindows = []; 816 foreach ($timePeriods as $tp) { 817 if (!isset($oldTimePeriods[$tp['timeperiodid']])) { 818 $newMaintenanceWindows[] = [ 819 'maintenanceid' => $maintenance['maintenanceid'], 820 'timeperiodid' => $tp['timeperiodid'] 821 ]; 822 } 823 } 824 DB::insert('maintenances_windows', $newMaintenanceWindows); 825 } 826 827 protected function addRelatedObjects(array $options, array $result) { 828 $result = parent::addRelatedObjects($options, $result); 829 830 // selectGroups 831 if ($options['selectGroups'] !== null && $options['selectGroups'] != API_OUTPUT_COUNT) { 832 $relationMap = $this->createRelationMap($result, 'maintenanceid', 'groupid', 'maintenances_groups'); 833 $groups = API::HostGroup()->get([ 834 'output' => $options['selectGroups'], 835 'hostgroupids' => $relationMap->getRelatedIds(), 836 'preservekeys' => true 837 ]); 838 $result = $relationMap->mapMany($result, $groups, 'groups'); 839 } 840 841 // selectHosts 842 if ($options['selectHosts'] !== null && $options['selectHosts'] != API_OUTPUT_COUNT) { 843 $relationMap = $this->createRelationMap($result, 'maintenanceid', 'hostid', 'maintenances_hosts'); 844 $groups = API::Host()->get([ 845 'output' => $options['selectHosts'], 846 'hostids' => $relationMap->getRelatedIds(), 847 'preservekeys' => true 848 ]); 849 $result = $relationMap->mapMany($result, $groups, 'hosts'); 850 } 851 852 // selectTimeperiods 853 if ($options['selectTimeperiods'] !== null && $options['selectTimeperiods'] != API_OUTPUT_COUNT) { 854 $relationMap = $this->createRelationMap($result, 'maintenanceid', 'timeperiodid', 'maintenances_windows'); 855 $timeperiods = API::getApiService()->select('timeperiods', [ 856 'output' => $options['selectTimeperiods'], 857 'filter' => ['timeperiodid' => $relationMap->getRelatedIds()], 858 'preservekeys' => true 859 ]); 860 $result = $relationMap->mapMany($result, $timeperiods, 'timeperiods'); 861 } 862 863 return $result; 864 } 865} 866