PageRenderTime 81ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/zabbix-2.0.1/frontends/php/api/classes/CScript.php

#
PHP | 610 lines | 426 code | 84 blank | 100 comment | 81 complexity | 1154f514f6954b226ecfdd3490c55f82 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. <?php
  2. /*
  3. ** Zabbix
  4. ** Copyright (C) 2000-2011 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. <?php
  22. /**
  23. * Class containing methods for operations with Scripts
  24. * @package API
  25. */
  26. class CScript extends CZBXAPI {
  27. protected $tableName = 'scripts';
  28. protected $tableAlias = 's';
  29. /**
  30. * Get Scripts data
  31. *
  32. * @param array $options
  33. * @param array $options['itemids']
  34. * @param array $options['hostids'] - depricated (very slow)
  35. * @param array $options['groupids']
  36. * @param array $options['triggerids']
  37. * @param array $options['scriptids']
  38. * @param boolean $options['status']
  39. * @param boolean $options['editable']
  40. * @param boolean $options['count']
  41. * @param string $options['pattern']
  42. * @param int $options['limit']
  43. * @param string $options['order']
  44. * @return array|int item data as array or false if error
  45. */
  46. public function get($options = array()) {
  47. $result = array();
  48. $userType = self::$userData['type'];
  49. $userid = self::$userData['userid'];
  50. // allowed columns for sorting
  51. $sortColumns = array('scriptid', 'name');
  52. $sqlParts = array(
  53. 'select' => array('scripts' => 's.scriptid'),
  54. 'from' => array('scripts s'),
  55. 'where' => array(),
  56. 'order' => array(),
  57. 'limit' => null
  58. );
  59. $defOptions = array(
  60. 'nodeids' => null,
  61. 'groupids' => null,
  62. 'hostids' => null,
  63. 'scriptids' => null,
  64. 'usrgrpids' => null,
  65. 'editable' => null,
  66. 'nopermissions' => null,
  67. // filter
  68. 'filter' => null,
  69. 'search' => null,
  70. 'searchByAny' => null,
  71. 'startSearch' => null,
  72. 'excludeSearch' => null,
  73. 'searchWildcardsEnabled'=> null,
  74. // output
  75. 'output' => API_OUTPUT_REFER,
  76. 'selectGroups' => null,
  77. 'selectHosts' => null,
  78. 'countOutput' => null,
  79. 'preservekeys' => null,
  80. 'sortfield' => '',
  81. 'sortorder' => '',
  82. 'limit' => null
  83. );
  84. $options = zbx_array_merge($defOptions, $options);
  85. if (is_array($options['output'])) {
  86. unset($sqlParts['select']['scripts']);
  87. $dbTable = DB::getSchema('scripts');
  88. $sqlParts['select']['scriptid'] = 's.scriptid';
  89. foreach ($options['output'] as $field) {
  90. if (isset($dbTable['fields'][$field])) {
  91. $sqlParts['select'][$field] = 's.'.$field;
  92. }
  93. }
  94. $options['output'] = API_OUTPUT_CUSTOM;
  95. }
  96. // editable + permission check
  97. if (USER_TYPE_SUPER_ADMIN == $userType) {
  98. }
  99. elseif (!is_null($options['editable'])) {
  100. return $result;
  101. }
  102. else {
  103. $sqlParts['from']['rights'] = 'rights r';
  104. $sqlParts['from']['users_groups'] = 'users_groups ug';
  105. $sqlParts['from']['hosts_groups'] = 'hosts_groups hg';
  106. $sqlParts['where'][] = 'hg.groupid=r.id';
  107. $sqlParts['where'][] = 'r.groupid=ug.usrgrpid';
  108. $sqlParts['where'][] = 'ug.userid='.$userid;
  109. $sqlParts['where'][] = '(hg.groupid=s.groupid OR s.groupid IS NULL)';
  110. $sqlParts['where'][] = '(ug.usrgrpid=s.usrgrpid OR s.usrgrpid IS NULL)';
  111. }
  112. // groupids
  113. if (!is_null($options['groupids'])) {
  114. zbx_value2array($options['groupids']);
  115. $options['groupids'][] = 0; // include all groups scripts
  116. if ($options['output'] != API_OUTPUT_SHORTEN) {
  117. $sqlParts['select']['scripts'] = 's.scriptid,s.groupid';
  118. }
  119. $sqlParts['where'][] = '('.DBcondition('s.groupid', $options['groupids']).' OR s.groupid IS NULL)';
  120. }
  121. // usrgrpids
  122. if (!is_null($options['usrgrpids'])) {
  123. zbx_value2array($options['usrgrpids']);
  124. $options['usrgrpids'][] = 0; // include all usrgrps scripts
  125. if ($options['output'] != API_OUTPUT_SHORTEN) {
  126. $sqlParts['select']['usrgrpid'] = 's.usrgrpid';
  127. }
  128. $sqlParts['where'][] = '('.DBcondition('s.usrgrpid', $options['usrgrpids']).' OR s.usrgrpid IS NULL)';
  129. }
  130. // hostids
  131. if (!is_null($options['hostids'])) {
  132. zbx_value2array($options['hostids']);
  133. // only fetch scripts from the same nodes as the hosts
  134. $hostNodeIds = array();
  135. foreach ($options['hostids'] as $hostId) {
  136. $hostNodeIds[] = id2nodeid($hostId);
  137. }
  138. $hostNodeIds = array_unique($hostNodeIds);
  139. if ($options['output'] != API_OUTPUT_SHORTEN) {
  140. $sqlParts['select']['hostid'] = 'hg.hostid';
  141. }
  142. $sqlParts['from']['hosts_groups'] = 'hosts_groups hg';
  143. $sqlParts['where'][] = '(('.DBcondition('hg.hostid', $options['hostids']).' AND hg.groupid=s.groupid)'.
  144. ' OR '.
  145. '(s.groupid IS NULL AND '.DBin_node('scriptid', $hostNodeIds).'))';
  146. }
  147. // scriptids
  148. if (!is_null($options['scriptids'])) {
  149. zbx_value2array($options['scriptids']);
  150. $sqlParts['where'][] = DBcondition('s.scriptid', $options['scriptids']);
  151. }
  152. // output
  153. if ($options['output'] == API_OUTPUT_EXTEND) {
  154. $sqlParts['select']['scripts'] = 's.*';
  155. }
  156. // search
  157. if (is_array($options['search'])) {
  158. zbx_db_search('scripts s', $options, $sqlParts);
  159. }
  160. // filter
  161. if (is_array($options['filter'])) {
  162. zbx_db_filter('scripts s', $options, $sqlParts);
  163. }
  164. // countOutput
  165. if (!is_null($options['countOutput'])) {
  166. $options['sortfield'] = '';
  167. $sqlParts['select'] = array('COUNT(DISTINCT s.scriptid) AS rowscount');
  168. }
  169. // sorting
  170. zbx_db_sorting($sqlParts, $options, $sortColumns, 's');
  171. // limit
  172. if (zbx_ctype_digit($options['limit']) && $options['limit']) {
  173. $sqlParts['limit'] = $options['limit'];
  174. }
  175. // node options
  176. $sqlParts = $this->applyQueryNodeOptions($this->tableName(), $this->tableAlias(), $options, $sqlParts);
  177. $scriptids = array();
  178. $res = DBselect($this->createSelectQueryFromParts($sqlParts), $sqlParts['limit']);
  179. while ($script = DBfetch($res)) {
  180. if ($options['countOutput']) {
  181. $result = $script['rowscount'];
  182. }
  183. else {
  184. $scriptids[$script['scriptid']] = $script['scriptid'];
  185. if ($options['output'] == API_OUTPUT_SHORTEN) {
  186. $result[$script['scriptid']] = array('scriptid' => $script['scriptid']);
  187. }
  188. else {
  189. if (!isset($result[$script['scriptid']])) {
  190. $result[$script['scriptid']] = array();
  191. }
  192. if (!is_null($options['selectGroups']) && !isset($result[$script['scriptid']]['groups'])) {
  193. $result[$script['scriptid']]['groups'] = array();
  194. }
  195. if (!is_null($options['selectHosts']) && !isset($result[$script['scriptid']]['hosts'])) {
  196. $result[$script['scriptid']]['hosts'] = array();
  197. }
  198. unset($script['hostid']);
  199. $result[$script['scriptid']] += $script;
  200. }
  201. }
  202. }
  203. if (!is_null($options['countOutput'])) {
  204. return $result;
  205. }
  206. // add related objects
  207. $result = $this->addRelatedObjects($options, $result);
  208. // removing keys (hash -> array)
  209. if (is_null($options['preservekeys'])) {
  210. $result = zbx_cleanHashes($result);
  211. }
  212. return $result;
  213. }
  214. /**
  215. * Get Script ID by host.name and item.key
  216. *
  217. * @param array $script
  218. * @param array $script['name']
  219. * @param array $script['hostid']
  220. * @return int|boolean
  221. */
  222. public function getObjects($script) {
  223. $result = array();
  224. $scriptids = array();
  225. $dbScripts = DBselect(
  226. 'SELECT s.scriptid'.
  227. ' FROM scripts s'.
  228. ' WHERE '.DBin_node('s.scriptid').
  229. ' AND s.name='.$script['name']
  230. );
  231. while ($script = DBfetch($dbScripts)) {
  232. $scriptids[$script['scriptid']] = $script['scriptid'];
  233. }
  234. if (!empty($scriptids)) {
  235. $result = $this->get(array('scriptids' => $scriptids, 'output' => API_OUTPUT_EXTEND));
  236. }
  237. return $result;
  238. }
  239. private function _clearData(&$scripts) {
  240. foreach ($scripts as $snum => $script) {
  241. if (isset($script['type']) && $script['type'] == ZBX_SCRIPT_TYPE_IPMI) {
  242. unset($scripts[$snum]['execute_on']);
  243. }
  244. }
  245. }
  246. /**
  247. * Add Scripts
  248. *
  249. * @param _array $scripts
  250. * @param array $script['name']
  251. * @param array $script['hostid']
  252. * @return boolean
  253. */
  254. public function create($scripts) {
  255. $scripts = zbx_toArray($scripts);
  256. if (USER_TYPE_SUPER_ADMIN != self::$userData['type']) {
  257. self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.'));
  258. }
  259. $scriptNames = array();
  260. foreach ($scripts as $script) {
  261. $scriptDbFields = array('name' => null, 'command' => null);
  262. if (!check_db_fields($scriptDbFields, $script)) {
  263. self::exception(ZBX_API_ERROR_PARAMETERS, _('Wrong fields for script.'));
  264. }
  265. if (isset($scriptNames[$script['name']])) {
  266. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Duplicate script name "%s".', $script['name']));
  267. }
  268. $scriptNames[$script['name']] = $script['name'];
  269. }
  270. $scriptsDB = $this->get(array(
  271. 'output' => API_OUTPUT_EXTEND,
  272. 'preservekeys' => true,
  273. 'filter' => array('name' => $scriptNames),
  274. 'limit' => 1
  275. ));
  276. if ($exScript = reset($scriptsDB)) {
  277. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Script "%s" already exists.', $exScript['name']));
  278. }
  279. $this->_clearData($scripts);
  280. $scriptids = DB::insert('scripts', $scripts);
  281. return array('scriptids' => $scriptids);
  282. }
  283. /**
  284. * Update Scripts
  285. *
  286. * @param _array $scripts
  287. * @param array $script['name']
  288. * @param array $script['hostid']
  289. * @return boolean
  290. */
  291. public function update($scripts) {
  292. $scripts = zbx_toHash($scripts, 'scriptid');
  293. $scriptids = array_keys($scripts);
  294. if (USER_TYPE_SUPER_ADMIN != self::$userData['type']) {
  295. self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.'));
  296. }
  297. $updScripts = $this->get(array(
  298. 'scriptids' => $scriptids,
  299. 'output' => API_OUTPUT_SHORTEN,
  300. 'preservekeys' => true
  301. ));
  302. $scriptNames = array();
  303. foreach ($scripts as $script) {
  304. if (!isset($updScripts[$script['scriptid']])) {
  305. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Script with scriptid "%s" does not exist.', $script['scriptid']));
  306. }
  307. if (isset($script['name'])) {
  308. if (isset($scriptNames[$script['name']])) {
  309. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Duplicate script name "%s".', $script['name']));
  310. }
  311. $scriptNames[$script['name']] = $script['name'];
  312. }
  313. }
  314. if (!empty($scriptNames)) {
  315. $dbScripts = $this->get(array(
  316. 'output' => API_OUTPUT_EXTEND,
  317. 'preservekeys' => true,
  318. 'filter' => array('name' => $scriptNames)
  319. ));
  320. foreach ($dbScripts as $exScript) {
  321. if (!isset($scripts[$exScript['scriptid']]) || bccomp($scripts[$exScript['scriptid']]['scriptid'], $exScript['scriptid']) != 0) {
  322. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Script "%s" already exists.', $exScript['name']));
  323. }
  324. }
  325. }
  326. $this->_clearData($scripts);
  327. $update = array();
  328. foreach ($scripts as $script) {
  329. $scriptid = $script['scriptid'];
  330. unset($script['scriptid']);
  331. $update[] = array(
  332. 'values' => $script,
  333. 'where' => array('scriptid' => $scriptid)
  334. );
  335. }
  336. DB::update('scripts', $update);
  337. return array('scriptids' => $scriptids);
  338. }
  339. /**
  340. * Delete Scripts
  341. *
  342. * @param _array $scriptids
  343. * @param array $scriptids
  344. * @return boolean
  345. */
  346. public function delete($scriptids) {
  347. $scriptids = zbx_toArray($scriptids);
  348. if (USER_TYPE_SUPER_ADMIN != self::$userData['type']) {
  349. self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.'));
  350. }
  351. if (empty($scriptids)) {
  352. self::exception(ZBX_API_ERROR_PARAMETERS, _('Cannot delete scripts. Empty input parameter "scriptids".'));
  353. }
  354. $dbScripts = $this->get(array(
  355. 'scriptids' => $scriptids,
  356. 'editable' => true,
  357. 'output' => API_OUTPUT_EXTEND,
  358. 'preservekeys' => true
  359. ));
  360. foreach ($scriptids as $scriptid) {
  361. if (isset($dbScripts[$scriptid])) {
  362. continue;
  363. }
  364. self::exception(ZBX_API_ERROR_PERMISSIONS, _s('Cannot delete scripts. Script with scriptid "%s" does not exist.', $scriptid));
  365. }
  366. $scriptActions = API::Action()->get(array(
  367. 'scriptids' => $scriptids,
  368. 'nopermissions' => true,
  369. 'preservekeys' => true,
  370. 'output' => array('actionid', 'name')
  371. ));
  372. foreach ($scriptActions as $action) {
  373. self::exception(ZBX_API_ERROR_PARAMETERS, _s('Cannot delete scripts. Script "%1$s" is used in action operation "%2$s".',
  374. $dbScripts[$action['scriptid']]['name'], $action['name']));
  375. }
  376. DB::delete('scripts', array('scriptid' => $scriptids));
  377. return array('scriptids' => $scriptids);
  378. }
  379. public function execute($data) {
  380. global $ZBX_SERVER, $ZBX_SERVER_PORT, $ZBX_MESSAGES;
  381. $scriptid = $data['scriptid'];
  382. $hostid = $data['hostid'];
  383. $alowedScripts = $this->get(array(
  384. 'hostids' => $hostid,
  385. 'scriptids' => $scriptid,
  386. 'output' => API_OUTPUT_SHORTEN,
  387. 'preservekeys' => true
  388. ));
  389. if (!isset($alowedScripts[$scriptid])) {
  390. self::exception(ZBX_API_ERROR_PERMISSIONS, _('You do not have permission to perform this operation.'));
  391. }
  392. if (!$socket = fsockopen($ZBX_SERVER, $ZBX_SERVER_PORT, $errorCode, $errorMsg, ZBX_SCRIPT_TIMEOUT)) {
  393. // remove warnings generated by fsockopen
  394. foreach ($ZBX_MESSAGES as $arrayNum => $fsockErrorCheck) {
  395. foreach ($fsockErrorCheck as $key => $value) {
  396. if ($key == 'message' && strpos($value, 'fsockopen()') !== false) {
  397. unset($ZBX_MESSAGES[$arrayNum]);
  398. }
  399. }
  400. }
  401. switch ($errorMsg) {
  402. case 'Connection refused':
  403. $dErrorMsg = _s("Connection to Zabbix server \"%s\" refused. Possible reasons:\n1. Incorrect server IP/DNS in the \"zabbix.conf.php\";\n2. Security environment (for example, SELinux) is blocking the connection;\n3. Zabbix server daemon not running;\n4. Firewall is blocking TCP connection.\n", $ZBX_SERVER);
  404. break;
  405. case 'No route to host':
  406. $dErrorMsg = _s("Zabbix server \"%s\" can not be reached. Possible reasons:\n1. Incorrect server IP/DNS in the \"zabbix.conf.php\";\n2. Incorrect network configuration.\n", $ZBX_SERVER);
  407. break;
  408. case 'Connection timed out':
  409. $dErrorMsg = _s("Connection to Zabbix server \"%s\" timed out. Possible reasons:\n1. Incorrect server IP/DNS in the \"zabbix.conf.php\";\n2. Firewall is blocking TCP connection.\n", $ZBX_SERVER);
  410. break;
  411. case 'php_network_getaddresses: getaddrinfo failed: Name or service not known':
  412. $dErrorMsg = _s("Connection to Zabbix server \"%s\" failed. Possible reasons:\n1. Incorrect server IP/DNS in the \"zabbix.conf.php\";\n2. Incorrect DNS server configuration.\n", $ZBX_SERVER);
  413. break;
  414. default:
  415. $dErrorMsg = '';
  416. }
  417. self::exception(ZBX_API_ERROR_INTERNAL, $dErrorMsg._('Error description').': '.$errorMsg);
  418. }
  419. $json = new CJSON();
  420. $array = array(
  421. 'request' => 'command',
  422. 'nodeid' => id2nodeid($hostid),
  423. 'scriptid' => $scriptid,
  424. 'hostid' => $hostid
  425. );
  426. $dataToSend = $json->encode($array, false);
  427. stream_set_timeout($socket, ZBX_SCRIPT_TIMEOUT);
  428. if (fwrite($socket, $dataToSend) === false) {
  429. self::exception(ZBX_API_ERROR_INTERNAL, _('Error description: can\'t send command, check connection.'));
  430. }
  431. $response = '';
  432. $pbl = ZBX_SCRIPT_BYTES_LIMIT > 8192 ? 8192 : ZBX_SCRIPT_BYTES_LIMIT; // PHP read bytes limit
  433. $now = time();
  434. $i = 0;
  435. while (!feof($socket)) {
  436. $i++;
  437. if ((time() - $now) >= ZBX_SCRIPT_TIMEOUT) {
  438. self::exception(ZBX_API_ERROR_INTERNAL,
  439. _('Error description: defined in "include/defines.inc.php" constant ZBX_SCRIPT_TIMEOUT timeout is reached. You can try to increase this value.'));
  440. }
  441. elseif (($i * $pbl) >= ZBX_SCRIPT_BYTES_LIMIT) {
  442. self::exception(ZBX_API_ERROR_INTERNAL,
  443. _('Error description: defined in "include/defines.inc.php" constant ZBX_SCRIPT_BYTES_LIMIT read bytes limit is reached. You can try to increase this value.'));
  444. }
  445. if (($out = fread($socket, $pbl)) !== false) {
  446. $response .= $out;
  447. }
  448. else {
  449. self::exception(ZBX_API_ERROR_INTERNAL, _('Error description: can\'t read script response, check connection.'));
  450. }
  451. }
  452. if (strlen($response) > 0) {
  453. $rcv = $json->decode($response, true);
  454. }
  455. else {
  456. self::exception(ZBX_API_ERROR_INTERNAL, _('Error description: empty response received.'));
  457. }
  458. fclose($socket);
  459. return $rcv;
  460. }
  461. /**
  462. * Returns all the scripts that are available on each given host.
  463. *
  464. * @param $hostIds
  465. *
  466. * @return array an array of scripts in the form of array($hostId => array($script1, $script2, ...), ...)
  467. */
  468. public function getScriptsByHosts($hostIds) {
  469. zbx_value2array($hostIds);
  470. $scriptsByHost = array();
  471. foreach ($hostIds as $hostid) {
  472. $scriptsByHost[$hostid] = array();
  473. }
  474. $scripts = $this->get(array(
  475. 'output' => API_OUTPUT_EXTEND,
  476. 'selectHosts' => API_OUTPUT_REFER,
  477. 'hostids' => $hostIds,
  478. 'sortfield' => 'name',
  479. 'preservekeys' => true
  480. ));
  481. foreach ($scripts as $script) {
  482. foreach ($script['hosts'] as $host) {
  483. $hostId = $host['hostid'];
  484. if (isset($scriptsByHost[$hostId])) {
  485. $scriptsByHost[$hostId][] = $script;
  486. }
  487. }
  488. }
  489. return $scriptsByHost;
  490. }
  491. protected function applyQueryNodeOptions($tableName, $tableAlias, array $options, array $sqlParts) {
  492. // only apply the node option if no specific ids are given
  493. if ($options['scriptids'] === null && $options['hostids'] === null && $options['groupids'] === null) {
  494. $sqlParts = parent::applyQueryNodeOptions($tableName, $tableAlias, $options, $sqlParts);
  495. }
  496. return $sqlParts;
  497. }
  498. protected function addRelatedObjects(array $options, array $result) {
  499. $result = parent::addRelatedObjects($options, $result);
  500. // allowed output options for [ select_* ] params
  501. $subselectsAllowedOutputs = array(API_OUTPUT_REFER, API_OUTPUT_EXTEND);
  502. // adding groups
  503. if (!is_null($options['selectGroups']) && str_in_array($options['selectGroups'], $subselectsAllowedOutputs)) {
  504. foreach ($result as $scriptid => $script) {
  505. $result[$scriptid]['groups'] = API::HostGroup()->get(array(
  506. 'output' => $options['selectGroups'],
  507. 'groupids' => ($script['groupid']) ? $script['groupid'] : null,
  508. 'editable' => ($script['host_access'] == PERM_READ_WRITE) ? true : null
  509. ));
  510. }
  511. }
  512. // adding hosts
  513. if (!is_null($options['selectHosts']) && str_in_array($options['selectHosts'], $subselectsAllowedOutputs)) {
  514. foreach ($result as $scriptid => $script) {
  515. $result[$scriptid]['hosts'] = API::Host()->get(array(
  516. 'output' => $options['selectHosts'],
  517. 'groupids' => ($script['groupid']) ? $script['groupid'] : null,
  518. 'editable' => ($script['host_access'] == PERM_READ_WRITE) ? true : null,
  519. 'nodeids' => id2nodeid($script['scriptid'])
  520. ));
  521. }
  522. }
  523. return $result;
  524. }
  525. }
  526. ?>