Example #1
0
 /**
  * Checks if any of the given host global macros already exist. If the macros are updated and
  * the "globalmacroid" field is set, the method will only fail, if a macro with a different globalmacroid exists.
  * Assumes the "macro", "hostmacroid" fields are valid.
  *
  * @param array $globalmacros
  * @param int $globalmacros[]['globalmacroid']
  * @param string $globalmacros[]['macro']
  * @param string $globalmacros[]['value']
  *
  * @throws APIException if any of the given macros already exist.
  */
 protected function checkIfGlobalMacrosDontRepeat(array $globalmacros)
 {
     if (!$globalmacros) {
         return;
     }
     $macro_names = [];
     $user_macro_parser = new CUserMacroParser();
     // Parse each macro, get unique names and, if context exists, narrow down the search.
     foreach ($globalmacros as $globalmacro) {
         $user_macro_parser->parse($globalmacro['macro']);
         $macro_name = $user_macro_parser->getMacro();
         $context = $user_macro_parser->getContext();
         if ($context === null) {
             $macro_names['{$' . $macro_name] = true;
         } else {
             // Narrow down the search for macros with contexts.
             $macro_names['{$' . $macro_name . ':'] = true;
         }
     }
     // When updating with empty array, don't select any data from database.
     $db_macros = API::getApiService()->select('globalmacro', ['output' => ['globalmacroid', 'macro'], 'search' => ['macro' => array_keys($macro_names)], 'searchByAny' => true]);
     $existing_macros = [];
     // Collect existing unique macro names and their contexts.
     foreach ($db_macros as $db_macro) {
         $user_macro_parser->parse($db_macro['macro']);
         $macro_name = $user_macro_parser->getMacro();
         $context = $user_macro_parser->getContext();
         $existing_macros[$macro_name][$db_macro['globalmacroid']] = $context;
     }
     // Compare each macro name and context to existing one.
     foreach ($globalmacros as $globalmacro) {
         $user_macro_parser->parse($globalmacro['macro']);
         $macro_name = $user_macro_parser->getMacro();
         $context = $user_macro_parser->getContext();
         if (array_key_exists($macro_name, $existing_macros) && in_array($context, $existing_macros[$macro_name], true)) {
             foreach ($existing_macros[$macro_name] as $globalmacroid => $existing_macro_context) {
                 if ((!array_key_exists('globalmacroid', $globalmacro) || bccomp($globalmacro['globalmacroid'], $globalmacroid) != 0) && $context === $existing_macro_context) {
                     self::exception(ZBX_API_ERROR_PARAMETERS, _s('Macro "%1$s" already exists.', $globalmacro['macro']));
                 }
             }
         }
     }
 }
Example #2
0
/**
 * Merge list of inherited and host-level macros.
 *
 * Returns an array like:
 *   array(
 *       '{$MACRO}' => array(
 *           'macro' => '{$MACRO}',
 *           'type' => 0x03,						<- MACRO_TYPE_INHERITED, MACRO_TYPE_HOSTMACRO or MACRO_TYPE_BOTH
 *           'value' => 'effective value',
 *           'hostmacroid' => 7532,                 <- optional
 *           'template' => array(                   <- optional
 *               'value' => 'template-level value'
 *               'templateid' => 10001,
 *               'name' => 'Template OS Linux'
 *           ),
 *           'global' => array(                     <- optional
 *               'value' => 'global-level value'
 *           )
 *       )
 *   )
 *
 * @param array $host_macros		the list of host macros
 * @param array $inherited_macros	the list of inherited macros (the output of the getInheritedMacros() function)
 *
 * @return array
 */
function mergeInheritedMacros(array $host_macros, array $inherited_macros)
{
    $user_macro_parser = new CUserMacroParser();
    foreach ($inherited_macros as &$inherited_macro) {
        $inherited_macro['type'] = MACRO_TYPE_INHERITED;
        $inherited_macro['value'] = array_key_exists('template', $inherited_macro) ? $inherited_macro['template']['value'] : $inherited_macro['global']['value'];
    }
    unset($inherited_macro);
    /*
     * Global macros and template macros are overwritten by host macros. Macros with contexts require additional
     * checking for contexts, since {$MACRO:} is the same as {$MACRO:""}.
     */
    foreach ($host_macros as &$host_macro) {
        if (array_key_exists($host_macro['macro'], $inherited_macros)) {
            $host_macro = array_merge($inherited_macros[$host_macro['macro']], $host_macro);
            unset($inherited_macros[$host_macro['macro']]);
        } else {
            /*
             * Cannot use array dereferencing because "$host_macro['macro']" may contain invalid macros
             * which results in empty array.
             */
            if ($user_macro_parser->parse($host_macro['macro']) == CParser::PARSE_SUCCESS) {
                $hst_macro = $user_macro_parser->getMacro();
                $hst_context = $user_macro_parser->getContext();
                if ($hst_context === null) {
                    $host_macro['type'] = 0x0;
                } else {
                    $match_found = false;
                    foreach ($inherited_macros as $inherited_macro => $inherited_values) {
                        // Safe to use array dereferencing since these values come from database.
                        $user_macro_parser->parse($inherited_macro);
                        $inh_macro = $user_macro_parser->getMacro();
                        $inh_context = $user_macro_parser->getContext();
                        if ($hst_macro === $inh_macro && $hst_context === $inh_context) {
                            $match_found = true;
                            $host_macro = array_merge($inherited_macros[$inherited_macro], $host_macro);
                            unset($inherited_macros[$inherited_macro]);
                            break;
                        }
                    }
                    if (!$match_found) {
                        $host_macro['type'] = 0x0;
                    }
                }
            } else {
                $host_macro['type'] = 0x0;
            }
        }
        $host_macro['type'] |= MACRO_TYPE_HOSTMACRO;
    }
    unset($host_macro);
    foreach ($inherited_macros as $inherited_macro) {
        $host_macros[] = $inherited_macro;
    }
    return $host_macros;
}
 /**
  * Get macros with values.
  *
  * @param array $data
  * @param array $data[<id>]			any identificator
  * @param array $data['hostids']	the list of host ids; [<hostid1>, ...]
  * @param array $data['macros']		the list of user macros to resolve, ['<usermacro1>' => null, ...]
  *
  * @return array
  */
 protected function getUserMacros(array $data)
 {
     // User macros.
     $hostids = [];
     foreach ($data as $element) {
         foreach ($element['hostids'] as $hostid) {
             $hostids[$hostid] = true;
         }
     }
     if (!$hostids) {
         return $data;
     }
     /*
      * @var array $host_templates
      * @var array $host_templates[<hostid>]		array of templates
      */
     $host_templates = [];
     /*
      * @var array  $host_macros
      * @var array  $host_macros[<hostid>]
      * @var array  $host_macros[<hostid>][<macro>]				macro base without curly braces
      * @var string $host_macros[<hostid>][<macro>]['value']		base macro value (without context); can be null
      * @var array  $host_macros[<hostid>][<macro>]['contexts']	context values; ['<context1>' => '<value1>', ...]
      */
     $host_macros = [];
     $user_macro_parser = new CUserMacroParser();
     do {
         $db_hosts = API::Host()->get(['hostids' => array_keys($hostids), 'templated_hosts' => true, 'output' => ['hostid'], 'selectParentTemplates' => ['templateid'], 'selectMacros' => ['macro', 'value']]);
         $hostids = [];
         foreach ($db_hosts as $db_host) {
             $host_templates[$db_host['hostid']] = zbx_objectValues($db_host['parentTemplates'], 'templateid');
             foreach ($db_host['macros'] as $db_macro) {
                 if ($user_macro_parser->parse($db_macro['macro']) != CParser::PARSE_SUCCESS) {
                     continue;
                 }
                 $macro = $user_macro_parser->getMacro();
                 $context = $user_macro_parser->getContext();
                 if (!array_key_exists($db_host['hostid'], $host_macros)) {
                     $host_macros[$db_host['hostid']] = [];
                 }
                 if (!array_key_exists($macro, $host_macros[$db_host['hostid']])) {
                     $host_macros[$db_host['hostid']][$macro] = ['value' => null, 'contexts' => []];
                 }
                 if ($context === null) {
                     $host_macros[$db_host['hostid']][$macro]['value'] = $db_macro['value'];
                 } else {
                     $host_macros[$db_host['hostid']][$macro]['contexts'][$context] = $db_macro['value'];
                 }
             }
         }
         foreach ($db_hosts as $db_host) {
             // Only unprocessed templates will be populated.
             foreach ($host_templates[$db_host['hostid']] as $templateid) {
                 if (!array_key_exists($templateid, $host_templates)) {
                     $hostids[$templateid] = true;
                 }
             }
         }
     } while ($hostids);
     $all_macros_resolved = true;
     $user_macro_parser = new CUserMacroParser();
     foreach ($data as &$element) {
         $hostids = [];
         foreach ($element['hostids'] as $hostid) {
             $hostids[$hostid] = true;
         }
         $hostids = array_keys($hostids);
         natsort($hostids);
         foreach ($element['macros'] as $usermacro => &$value) {
             if ($user_macro_parser->parse($usermacro) == CParser::PARSE_SUCCESS) {
                 $value = $this->getHostUserMacros($hostids, $user_macro_parser->getMacro(), $user_macro_parser->getContext(), $host_templates, $host_macros);
                 if ($value['value'] === null) {
                     $all_macros_resolved = false;
                 }
             } else {
                 // This macro cannot be resolved.
                 $value = ['value' => $usermacro, 'value_default' => null];
             }
         }
         unset($value);
     }
     unset($element);
     if (!$all_macros_resolved) {
         // Global macros.
         $db_global_macros = API::UserMacro()->get(['output' => ['macro', 'value'], 'globalmacro' => true]);
         /*
          * @var array  $global_macros
          * @var array  $global_macros[<macro>]				macro base without curly braces
          * @var string $global_macros[<macro>]['value']		base macro value (without context); can be null
          * @var array  $global_macros[<macro>]['contexts']	context values; ['<context1>' => '<value1>', ...]
          */
         $global_macros = [];
         foreach ($db_global_macros as $db_global_macro) {
             if ($user_macro_parser->parse($db_global_macro['macro']) == CParser::PARSE_SUCCESS) {
                 $macro = $user_macro_parser->getMacro();
                 $context = $user_macro_parser->getContext();
                 if (!array_key_exists($macro, $global_macros)) {
                     $global_macros[$macro] = ['value' => null, 'contexts' => []];
                 }
                 if ($context === null) {
                     $global_macros[$macro]['value'] = $db_global_macro['value'];
                 } else {
                     $global_macros[$macro]['contexts'][$context] = $db_global_macro['value'];
                 }
             }
         }
         foreach ($data as &$element) {
             foreach ($element['macros'] as $usermacro => &$value) {
                 if ($value['value'] === null && $user_macro_parser->parse($usermacro) == CParser::PARSE_SUCCESS) {
                     $macro = $user_macro_parser->getMacro();
                     $context = $user_macro_parser->getContext();
                     if (array_key_exists($macro, $global_macros)) {
                         if ($context !== null && array_key_exists($context, $global_macros[$macro]['contexts'])) {
                             $value['value'] = $global_macros[$macro]['contexts'][$context];
                         } elseif ($global_macros[$macro]['value'] !== null) {
                             if ($context === null) {
                                 $value['value'] = $global_macros[$macro]['value'];
                             } elseif ($value['value_default'] === null) {
                                 $value['value_default'] = $global_macros[$macro]['value'];
                             }
                         }
                     }
                 }
             }
             unset($value);
         }
         unset($element);
     }
     foreach ($data as &$element) {
         foreach ($element['macros'] as $usermacro => &$value) {
             if ($value['value'] !== null) {
                 $value = $value['value'];
             } elseif ($value['value_default'] !== null) {
                 $value = $value['value_default'];
             } else {
                 // Unresolved macro.
                 $value = $usermacro;
             }
         }
         unset($value);
     }
     unset($element);
     return $data;
 }