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 * Converter for converting import data from 2.x to 3.0.
24 */
25class C20ImportConverter extends CConverter {
26
27	/**
28	 * Item key convertation.
29	 *
30	 * @var C20ItemKeyConverter
31	 */
32	protected $itemKeyConverter;
33
34	/**
35	 * Converter used for converting trigger expressions from 2.2 to 2.4 format.
36	 *
37	 * @var CConverter
38	 */
39	protected $triggerExpressionConverter;
40
41	public function __construct() {
42		$this->itemKeyConverter = new C20ItemKeyConverter();
43		$this->triggerExpressionConverter = new C20TriggerConverter();
44	}
45
46	public function convert($data) {
47		$data['zabbix_export']['version'] = '3.0';
48
49		if (array_key_exists('hosts', $data['zabbix_export'])) {
50			$data['zabbix_export']['hosts'] = $this->convertHosts($data['zabbix_export']['hosts']);
51		}
52		if (array_key_exists('templates', $data['zabbix_export'])) {
53			$data['zabbix_export']['templates'] = $this->convertTemplates($data['zabbix_export']['templates']);
54		}
55		if (array_key_exists('graphs', $data['zabbix_export'])) {
56			$data['zabbix_export']['graphs'] = $this->convertGraphs($data['zabbix_export']['graphs']);
57		}
58		if (array_key_exists('triggers', $data['zabbix_export'])) {
59			$data['zabbix_export']['triggers'] = $this->convertTriggers($data['zabbix_export']['triggers']);
60		}
61		if (array_key_exists('screens', $data['zabbix_export'])) {
62			$data['zabbix_export']['screens'] = $this->convertScreens($data['zabbix_export']['screens']);
63		}
64		if (array_key_exists('maps', $data['zabbix_export'])) {
65			$data['zabbix_export']['maps'] = $this->convertMaps($data['zabbix_export']['maps']);
66		}
67
68		return $data;
69	}
70
71	/**
72	 * Convert host elements.
73	 *
74	 * @param array $hosts
75	 *
76	 * @return array
77	 */
78	protected function convertHosts(array $hosts) {
79		foreach ($hosts as &$host) {
80			if (array_key_exists('interfaces', $host)) {
81				$host['interfaces'] = $this->convertHostInterfaces($host['interfaces']);
82			}
83			if (array_key_exists('items', $host)) {
84				$host['items'] = $this->convertItems($host['items']);
85			}
86			if (array_key_exists('discovery_rules', $host)) {
87				$host['discovery_rules'] = $this->convertDiscoveryRules($host['discovery_rules']);
88			}
89		}
90		unset($host);
91
92		return $hosts;
93	}
94
95	/**
96	 * Convert template elements.
97	 *
98	 * @param array $templates
99	 *
100	 * @return array
101	 */
102	protected function convertTemplates(array $templates) {
103		foreach ($templates as &$template) {
104			if (array_key_exists('items', $template)) {
105				$template['items'] = $this->convertItems($template['items']);
106			}
107			if (array_key_exists('discovery_rules', $template)) {
108				$template['discovery_rules'] = $this->convertDiscoveryRules($template['discovery_rules']);
109			}
110			if (array_key_exists('screens', $template)) {
111				$template['screens'] = $this->convertScreens($template['screens']);
112			}
113		}
114		unset($template);
115
116		return $templates;
117	}
118
119	/**
120	 * Convert item elements.
121	 *
122	 * @param array $items
123	 *
124	 * @return array
125	 */
126	protected function convertItems(array $items) {
127		foreach ($items as &$item) {
128			if ($item['status'] == ITEM_STATUS_NOTSUPPORTED) {
129				$item['status'] = ITEM_STATUS_ACTIVE;
130			}
131
132			$item['key'] = $this->itemKeyConverter->convert($item['key']);
133		}
134		unset($item);
135
136		return $items;
137	}
138
139	/**
140	 * Convert interface elements.
141	 *
142	 * @param array $interfaces
143	 *
144	 * @return array
145	 */
146	protected function convertHostInterfaces(array $interfaces) {
147		foreach ($interfaces as &$interface) {
148			if (!array_key_exists('bulk', $interface) && $interface['type'] == INTERFACE_TYPE_SNMP) {
149				$interface['bulk'] = SNMP_BULK_ENABLED;
150			}
151		}
152		unset($interface);
153
154		return $interfaces;
155	}
156
157	/**
158	 * Convert trigger elements.
159	 *
160	 * @param array $triggers
161	 *
162	 * @return array
163	 */
164	protected function convertTriggers(array $triggers) {
165		foreach ($triggers as &$trigger) {
166			if (array_key_exists('dependencies', $trigger)) {
167				foreach ($trigger['dependencies'] as &$dependency) {
168					$dependency['expression'] = $this->triggerExpressionConverter->convert($dependency['expression']);
169				}
170				unset($dependency);
171			}
172
173			$trigger['expression'] = $this->triggerExpressionConverter->convert($trigger['expression']);
174		}
175		unset($trigger);
176
177		return $triggers;
178	}
179
180	/**
181	 * Convert screens.
182	 *
183	 * @param array $screens
184	 *
185	 * @return array
186	 */
187	protected function convertScreens(array $screens) {
188		foreach ($screens as &$screen) {
189			if (array_key_exists('screen_items', $screen)) {
190				$screen['screen_items'] = $this->convertScreenItems($screen['screen_items']);
191			}
192		}
193		unset($screen);
194
195		return $screens;
196	}
197
198	/**
199	 * Convert screen items.
200	 *
201	 * @param array $screen_items
202	 *
203	 * @return array
204	 */
205	protected function convertScreenItems(array $screen_items) {
206		foreach ($screen_items as &$screen_item) {
207			if ($screen_item['rowspan'] == 0) {
208				$screen_item['rowspan'] = 1;
209			}
210			if ($screen_item['colspan'] == 0) {
211				$screen_item['colspan'] = 1;
212			}
213
214			if (zbx_is_int($screen_item['resourcetype'])) {
215				switch ($screen_item['resourcetype']) {
216					case SCREEN_RESOURCE_SIMPLE_GRAPH:
217					case SCREEN_RESOURCE_PLAIN_TEXT:
218						$screen_item['resource']['key'] =
219							$this->itemKeyConverter->convert($screen_item['resource']['key']);
220						break;
221				}
222			}
223		}
224		unset($screen_item);
225
226		return $screen_items;
227	}
228
229	/**
230	 * Convert map elements.
231	 *
232	 * @param array $maps
233	 *
234	 * @return array
235	 */
236	protected function convertMaps(array $maps) {
237		foreach ($maps as &$map) {
238			if (array_key_exists('selements', $map)) {
239				foreach ($map['selements'] as &$selement) {
240					if ($selement['elementtype'] == SYSMAP_ELEMENT_TYPE_TRIGGER) {
241						$selement['element']['expression'] = $this->triggerExpressionConverter->convert(
242							$selement['element']['expression']
243						);
244					}
245				}
246				unset($selement);
247			}
248
249			foreach ($map['links'] as &$link) {
250				if (array_key_exists('linktriggers', $link)) {
251					foreach ($link['linktriggers'] as &$linktrigger) {
252						$linktrigger['trigger']['expression'] = $this->triggerExpressionConverter->convert(
253							$linktrigger['trigger']['expression']
254						);
255					}
256					unset($linktrigger);
257				}
258			}
259			unset($link);
260		}
261		unset($map);
262
263		return $maps;
264	}
265
266	/**
267	 * Convert discovery rule elements.
268	 *
269	 * @param array $discovery_rules
270	 *
271	 * @return array
272	 */
273	protected function convertDiscoveryRules(array $discovery_rules) {
274		foreach ($discovery_rules as &$discovery_rule) {
275			if ($discovery_rule['status'] == ITEM_STATUS_NOTSUPPORTED) {
276				$discovery_rule['status'] = ITEM_STATUS_ACTIVE;
277			}
278
279			if (in_array($discovery_rule['type'], [ITEM_TYPE_SNMPV1, ITEM_TYPE_SNMPV2C, ITEM_TYPE_SNMPV3])) {
280				$param = CItemKey::quoteParam($discovery_rule['snmp_oid']);
281				if ($param !== false) {
282					$discovery_rule['snmp_oid'] = 'discovery[{#SNMPVALUE},'.$param.']';
283				}
284			}
285
286			if (!array_key_exists('host_prototypes', $discovery_rule)) {
287				$discovery_rule['host_prototypes'] = [];
288			}
289
290			$discovery_rule['filter'] = $this->convertDiscoveryRuleFilter($discovery_rule['filter']);
291			$discovery_rule['item_prototypes'] = $this->convertItemPrototypes($discovery_rule['item_prototypes']);
292			$discovery_rule['graph_prototypes'] = $this->convertGraphs($discovery_rule['graph_prototypes']);
293			$discovery_rule['trigger_prototypes'] =
294				$this->convertTriggerPrototypes($discovery_rule['trigger_prototypes']);
295		}
296		unset($discovery_rule);
297
298		return $discovery_rules;
299	}
300
301	/**
302	 * Convert item prototype elements.
303	 *
304	 * @param array $item_prototypes
305	 *
306	 * @return array
307	 */
308	protected function convertItemPrototypes(array $item_prototypes) {
309		foreach ($item_prototypes as &$item_prototype) {
310			$item_prototype['key'] = $this->itemKeyConverter->convert($item_prototype['key']);
311		}
312		unset($item_prototype);
313
314		return $item_prototypes;
315	}
316
317	/**
318	 * Convert graph elements.
319	 *
320	 * @param array $graphs
321	 *
322	 * @return array
323	 */
324	protected function convertGraphs(array $graphs) {
325		foreach ($graphs as &$graph) {
326			$graph['graph_items'] = $this->convertGraphItems($graph['graph_items']);
327
328			if (zbx_is_int($graph['ymin_type_1'])) {
329				if ($graph['ymin_type_1'] == GRAPH_YAXIS_TYPE_ITEM_VALUE) {
330					$graph['ymin_item_1']['key'] = $this->itemKeyConverter->convert($graph['ymin_item_1']['key']);
331				}
332			}
333
334			if (zbx_is_int($graph['ymax_type_1'])) {
335				if ($graph['ymax_type_1'] == GRAPH_YAXIS_TYPE_ITEM_VALUE) {
336					$graph['ymax_item_1']['key'] = $this->itemKeyConverter->convert($graph['ymax_item_1']['key']);
337				}
338			}
339		}
340		unset($graph);
341
342		return $graphs;
343	}
344
345	/**
346	 * Convert graph items elements.
347	 *
348	 * @param array $graph_items
349	 *
350	 * @return array
351	 */
352	protected function convertGraphItems(array $graph_items) {
353		foreach ($graph_items as &$graph_item) {
354			$graph_item['item']['key'] = $this->itemKeyConverter->convert($graph_item['item']['key']);
355		}
356		unset($graph_item);
357
358		return $graph_items;
359	}
360
361	/**
362	 * Convert trigger prototype elements.
363	 *
364	 * @param array $trigger_prototypes
365	 *
366	 * @return array
367	 */
368	protected function convertTriggerPrototypes(array $trigger_prototypes) {
369		foreach ($trigger_prototypes as &$trigger_prototype) {
370			$trigger_prototype['expression'] =
371				$this->triggerExpressionConverter->convert($trigger_prototype['expression']);
372		}
373		unset($trigger_prototype);
374
375		return $trigger_prototypes;
376	}
377
378	/**
379	 * Convert filters from the 2.0 and 2.2 string representations to a 2.4 array.
380	 *
381	 * @param mixed $filter
382	 * @return array
383	 */
384	protected function convertDiscoveryRuleFilter($filter) {
385		// string filters were exported as "{#MACRO}:regex"
386		if (is_string($filter)) {
387			$new_filter = [
388				'evaltype' => CONDITION_EVAL_TYPE_AND_OR,
389				'formula' => '',
390				'conditions' => []
391			];
392
393			if (strpos($filter, ':') !== false && $filter !== ':') {
394				list ($macro, $value) = explode(':', $filter);
395
396				$new_filter['conditions'][] = [
397					'macro' => $macro,
398					'value' => $value,
399					'operator' => CONDITION_OPERATOR_REGEXP
400				];
401			}
402
403			return $new_filter;
404		}
405
406		return $filter;
407	}
408}
409