blob: 362712f6432cb4bb44ab3331d541e0eb087f1a19 [file] [log] [blame]
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 1.8 from src/site/markdown/metron-platform/metron-common/index.md at 2019-05-14
| Rendered using Apache Maven Fluido Skin 1.7
-->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="Date-Revision-yyyymmdd" content="20190514" />
<meta http-equiv="Content-Language" content="en" />
<title>Metron &#x2013; Contents</title>
<link rel="stylesheet" href="../../css/apache-maven-fluido-1.7.min.css" />
<link rel="stylesheet" href="../../css/site.css" />
<link rel="stylesheet" href="../../css/print.css" media="print" />
<script type="text/javascript" src="../../js/apache-maven-fluido-1.7.min.js"></script>
<script type="text/javascript">
$( document ).ready( function() { $( '.carousel' ).carousel( { interval: 3500 } ) } );
</script>
</head>
<body class="topBarDisabled">
<div class="container-fluid">
<div id="banner">
<div class="pull-left"><a href="http://metron.apache.org/" id="bannerLeft"><img src="../../images/metron-logo.png" alt="Apache Metron" width="148px" height="48px"/></a></div>
<div class="pull-right"></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li class=""><a href="http://www.apache.org" class="externalLink" title="Apache">Apache</a><span class="divider">/</span></li>
<li class=""><a href="http://metron.apache.org/" class="externalLink" title="Metron">Metron</a><span class="divider">/</span></li>
<li class=""><a href="../../index.html" title="Documentation">Documentation</a><span class="divider">/</span></li>
<li class="active ">Contents</li>
<li id="publishDate" class="pull-right"><span class="divider">|</span> Last Published: 2019-05-14</li>
<li id="projectVersion" class="pull-right">Version: 0.7.1</li>
</ul>
</div>
<div class="row-fluid">
<div id="leftColumn" class="span2">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">User Documentation</li>
<li><a href="../../index.html" title="Metron"><span class="icon-chevron-down"></span>Metron</a>
<ul class="nav nav-list">
<li><a href="../../CONTRIBUTING.html" title="CONTRIBUTING"><span class="none"></span>CONTRIBUTING</a></li>
<li><a href="../../Upgrading.html" title="Upgrading"><span class="none"></span>Upgrading</a></li>
<li><a href="../../metron-analytics/index.html" title="Analytics"><span class="icon-chevron-right"></span>Analytics</a></li>
<li><a href="../../metron-contrib/metron-docker/index.html" title="Docker"><span class="none"></span>Docker</a></li>
<li><a href="../../metron-contrib/metron-performance/index.html" title="Performance"><span class="none"></span>Performance</a></li>
<li><a href="../../metron-deployment/index.html" title="Deployment"><span class="icon-chevron-right"></span>Deployment</a></li>
<li><a href="../../metron-interface/index.html" title="Interface"><span class="icon-chevron-right"></span>Interface</a></li>
<li><a href="../../metron-platform/index.html" title="Platform"><span class="icon-chevron-down"></span>Platform</a>
<ul class="nav nav-list">
<li><a href="../../metron-platform/Performance-tuning-guide.html" title="Performance-tuning-guide"><span class="none"></span>Performance-tuning-guide</a></li>
<li class="active"><a href="#"><span class="none"></span>Common</a></li>
<li><a href="../../metron-platform/metron-data-management/index.html" title="Data-management"><span class="none"></span>Data-management</a></li>
<li><a href="../../metron-platform/metron-elasticsearch/index.html" title="Elasticsearch"><span class="none"></span>Elasticsearch</a></li>
<li><a href="../../metron-platform/metron-enrichment/index.html" title="Enrichment"><span class="icon-chevron-right"></span>Enrichment</a></li>
<li><a href="../../metron-platform/metron-hbase-server/index.html" title="Hbase-server"><span class="none"></span>Hbase-server</a></li>
<li><a href="../../metron-platform/metron-indexing/index.html" title="Indexing"><span class="none"></span>Indexing</a></li>
<li><a href="../../metron-platform/metron-job/index.html" title="Job"><span class="none"></span>Job</a></li>
<li><a href="../../metron-platform/metron-management/index.html" title="Management"><span class="none"></span>Management</a></li>
<li><a href="../../metron-platform/metron-parsing/index.html" title="Parsing"><span class="icon-chevron-right"></span>Parsing</a></li>
<li><a href="../../metron-platform/metron-pcap-backend/index.html" title="Pcap-backend"><span class="none"></span>Pcap-backend</a></li>
<li><a href="../../metron-platform/metron-solr/index.html" title="Solr"><span class="none"></span>Solr</a></li>
<li><a href="../../metron-platform/metron-writer/index.html" title="Writer"><span class="none"></span>Writer</a></li>
</ul>
</li>
<li><a href="../../metron-sensors/index.html" title="Sensors"><span class="icon-chevron-right"></span>Sensors</a></li>
<li><a href="../../metron-stellar/stellar-3rd-party-example/index.html" title="Stellar-3rd-party-example"><span class="none"></span>Stellar-3rd-party-example</a></li>
<li><a href="../../metron-stellar/stellar-common/index.html" title="Stellar-common"><span class="icon-chevron-right"></span>Stellar-common</a></li>
<li><a href="../../metron-stellar/stellar-zeppelin/index.html" title="Stellar-zeppelin"><span class="none"></span>Stellar-zeppelin</a></li>
<li><a href="../../use-cases/index.html" title="Use-cases"><span class="icon-chevron-right"></span>Use-cases</a></li>
</ul>
</li>
</ul>
<hr />
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy"><img class="builtBy" alt="Built by Maven" src="../../images/logos/maven-feather.png" /></a>
</div>
</div>
</div>
<div id="bodyColumn" class="span10" >
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<h1>Contents</h1>
<p><a name="Contents"></a></p>
<ul>
<li><a href="#Stellar_Language">Stellar Language</a></li>
<li><a href="#High_Level_Architecture">High Level Architecture</a></li>
<li><a href="#Global_Configuration">Global Configuration</a></li>
<li><a href="#Validation_Framework">Validation Framework</a></li>
<li><a href="#Management_Utility">Management Utility</a></li>
<li><a href="topology-errors/index.html">Topology Errors</a></li>
<li><a href="#Performance_Logging">Performance Logging</a></li>
<li><a href="#Metron_Debugging">Metron Debugging</a></li>
</ul>
<p><a name="Stellar_Language"></a></p>
<h1>Stellar Language</h1>
<p>For a variety of components (threat intelligence triage and field transformations) we have the need to do simple computation and transformation using the data from messages as variables. For those purposes, there exists a simple, scaled down DSL created to do simple computation and transformation.</p>
<p>The query language supports the following:</p>
<ul>
<li>Referencing fields in the enriched JSON</li>
<li>String literals are quoted with either <tt>'</tt> or <tt>&quot;</tt>, and support escaping for <tt>'</tt>, <tt>&quot;</tt>, <tt>\t</tt>, <tt>\r</tt>, <tt>\n</tt>, and backslash</li>
<li>Simple boolean operations: <tt>and</tt>, <tt>not</tt>, <tt>or</tt>
<ul>
<li>Boolean expressions are short-circuited (e.g. <tt>true or FUNC()</tt> would never execute <tt>FUNC</tt>)</li>
</ul>
</li>
<li>Simple arithmetic operations: <tt>*</tt>, <tt>/</tt>, <tt>+</tt>, <tt>-</tt> on real numbers or integers</li>
<li>Simple comparison operations <tt>&lt;</tt>, <tt>&gt;</tt>, <tt>&lt;=</tt>, <tt>&gt;=</tt></li>
<li>Simple equality comparison operations <tt>==</tt>, <tt>!=</tt></li>
<li>if/then/else comparisons (i.e. <tt>if var1 &lt; 10 then 'less than 10' else '10 or more'</tt>)</li>
<li>Determining whether a field exists (via <tt>exists</tt>)</li>
<li>An <tt>in</tt> operator that works like the <tt>in</tt> in Python</li>
<li>The ability to have parenthesis to make order of operations explicit</li>
<li>User defined functions, including Lambda expressions</li>
</ul>
<p>For documentation of Stellar, please see the <a href="../../metron-stellar/stellar-common/index.html">Stellar README</a>.</p>
<p><a name="Global_Configuration"></a></p>
<h1>Global Configuration</h1>
<p>The format of the global enrichment is a JSON String to Object map. This is intended for configuration which is non sensor specific configuration.</p>
<p>This configuration is stored in zookeeper, but looks something like</p>
<div>
<div>
<pre class="source">{
&quot;es.clustername&quot;: &quot;metron&quot;,
&quot;es.ip&quot;: &quot;node1&quot;,
&quot;es.port&quot;: &quot;9300&quot;,
&quot;es.date.format&quot;: &quot;yyyy.MM.dd.HH&quot;,
&quot;parser.error.topic&quot;: &quot;indexing&quot;,
&quot;fieldValidations&quot; : [
{
&quot;input&quot; : [ &quot;ip_src_addr&quot;, &quot;ip_dst_addr&quot; ],
&quot;validation&quot; : &quot;IP&quot;,
&quot;config&quot; : {
&quot;type&quot; : &quot;IPV4&quot;
}
}
]
}
</pre></div></div>
<p>Various parts of our stack uses the global config are documented throughout the Metron documentation, but a convenient index is provided here:</p>
<table border="0" class="table table-striped">
<thead>
<tr class="a">
<th> Property Name </th>
<th> Subsystem </th>
<th> Type </th>
<th> Ambari Property </th></tr>
</thead><tbody>
<tr class="b">
<td> <a href="../metron-elasticsearch/index.html#es.clustername"><tt>es.clustername</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> <tt>es_cluster_name</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-elasticsearch/index.html#es.ip"><tt>es.ip</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> <tt>es_hosts</tt> &amp; <tt>es_port</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-elasticsearch/index.html#es.port"><tt>es.port</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../metron-elasticsearch/index.html#es.date.format"><tt>es.date.format</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> <tt>es_date_format</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-elasticsearch/index.html#es.client.settings"><tt>es.client.settings</tt></a> </td>
<td> Indexing </td>
<td> Object </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.zookeeper</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> <tt>solr_zookeeper_url</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.commitPerBatch</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.commit.soft</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="b">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.commit.waitSearcher</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.commit.waitFlush</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="b">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.collection</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../metron-solr/index.html#configuration"><tt>solr.http.config</tt></a> </td>
<td> Indexing </td>
<td> String </td>
<td> N/A </td></tr>
<tr class="b">
<td> <a href="#validation-framework"><tt>fieldValidations</tt></a> </td>
<td> Parsing </td>
<td> Object </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../metron-parsers/index.html#parser.error.topic"><tt>parser.error.topic</tt></a> </td>
<td> Parsing </td>
<td> String </td>
<td> <tt>parser_error_topic</tt> </td></tr>
<tr class="b">
<td> <a href="../../metron-stellar/stellar-common/index.html#stellar.function.paths"><tt>stellar.function.paths</tt></a> </td>
<td> Stellar </td>
<td> CSV String </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../../metron-stellar/stellar-common/index.html#stellarfunctionresolverincludesexcludes"><tt>stellar.function.resolver.includes</tt></a> </td>
<td> Stellar </td>
<td> CSV String </td>
<td> N/A </td></tr>
<tr class="b">
<td> <a href="../../metron-stellar/stellar-common/index.html#stellarfunctionresolverincludesexcludes"><tt>stellar.function.resolver.excludes</tt></a> </td>
<td> Stellar </td>
<td> CSV String </td>
<td> N/A </td></tr>
<tr class="a">
<td> <a href="../../metron-analytics/metron-profiler-storm/index.html#profiler.period.duration"><tt>profiler.period.duration</tt></a> </td>
<td> Profiler </td>
<td> Integer </td>
<td> <tt>profiler_period_duration</tt> </td></tr>
<tr class="b">
<td> <a href="../../metron-analytics/metron-profiler-storm/index.html#profiler.period.duration.units"><tt>profiler.period.duration.units</tt></a> </td>
<td> Profiler </td>
<td> String </td>
<td> <tt>profiler_period_units</tt> </td></tr>
<tr class="a">
<td> <a href="../../metron-analytics/metron-profiler-storm/index.html#profilerperiodduration"><tt>profiler.client.period.duration</tt></a> </td>
<td> Profiler </td>
<td> Integer </td>
<td> <tt>profiler_period_duration</tt> </td></tr>
<tr class="b">
<td> <a href="../../metron-analytics/metron-profiler-storm/index.html#profilerperioddurationunits"><tt>profiler.client.period.duration.units</tt></a> </td>
<td> Profiler </td>
<td> String </td>
<td> <tt>profiler_period_units</tt> </td></tr>
<tr class="a">
<td> <a href="../../metron-analytics/metron-profiler-storm/index.html#profiler.writer.batchSize"><tt>profiler.writer.batchSize</tt></a> </td>
<td> Profiler </td>
<td> Integer </td>
<td> <tt>profiler_kafka_writer_batch_size</tt> </td></tr>
<tr class="b">
<td> <a href="../../metron-analytics/metron-profiler-storm/index.html#profiler.writer.batchTimeout"><tt>profiler.writer.batchTimeout</tt></a> </td>
<td> Profiler </td>
<td> Integer </td>
<td> <tt>profiler_kafka_writer_batch_timeout</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-indexing/index.html#update.hbase.table"><tt>update.hbase.table</tt></a> </td>
<td> REST/Indexing </td>
<td> String </td>
<td> <tt>update_hbase_table</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-indexing/index.html#update.hbase.cf"><tt>update.hbase.cf</tt></a> </td>
<td> REST/Indexing </td>
<td> String </td>
<td> <tt>update_hbase_cf</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-interface/metron-rest/index.html"><tt>user.settings.hbase.table</tt></a> </td>
<td> REST/Indexing </td>
<td> String </td>
<td> <tt>user_settings_hbase_table</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-interface/metron-rest/index.html"><tt>user.settings.hbase.cf</tt></a> </td>
<td> REST/Indexing </td>
<td> String </td>
<td> <tt>user_settings_hbase_cf</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-enrichment/metron-enrichment-common/index.html#geo.hdfs.file"><tt>geo.hdfs.file</tt></a> </td>
<td> Enrichment </td>
<td> String </td>
<td> <tt>geo_hdfs_file</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-enrichment/metron-enrichment-common/index.html#enrichment.writer.batchSize"><tt>enrichment.writer.batchSize</tt></a> </td>
<td> Enrichment </td>
<td> Integer </td>
<td> <tt>enrichment_kafka_writer_batch_size</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-enrichment/metron-enrichment-common/index.html#enrichment.writer.batchTimeout"><tt>enrichment.writer.batchTimeout</tt></a> </td>
<td> Enrichment </td>
<td> Integer </td>
<td> <tt>enrichment_kafka_writer_batch_timeout</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-hbase-server/index.html#enrichment.list.hbase.provider.impl"><tt>enrichment.list.hbase.provider.impl</tt></a> </td>
<td> Enrichment </td>
<td> String </td>
<td> <tt>enrichment_list_hbase_provider_impl</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-hbase-server/index.html#enrichment.list.hbase.table"><tt>enrichment.list.hbase.table</tt></a> </td>
<td> Enrichment </td>
<td> String </td>
<td> <tt>enrichment_list_hbase_table</tt> </td></tr>
<tr class="b">
<td> <a href="../metron-hbase-server/index.html#enrichment.list.hbase.cf"><tt>enrichment.list.hbase.cf</tt></a> </td>
<td> Enrichment </td>
<td> String </td>
<td> <tt>enrichment_list_hbase_cf</tt> </td></tr>
<tr class="a">
<td> <a href="../metron-enrichment/index.html#geo.hdfs.file"><tt>geo.hdfs.file</tt></a> </td>
<td> Enrichment </td>
<td> String </td>
<td> <tt>geo_hdfs_file</tt> </td></tr>
<tr class="b">
<td> <a href="../../metron-interface/metron-alerts/index.html#source.type.field"><tt>source.type.field</tt></a> </td>
<td> UI </td>
<td> String </td>
<td> <tt>source_type_field</tt> </td></tr>
<tr class="a">
<td> <a href="../../metron-interface/metron-alerts/index.html#threat.triage.score.field"><tt>threat.triage.score.field</tt></a> </td>
<td> UI </td>
<td> String </td>
<td> <tt>threat_triage_score_field</tt> </td></tr>
</tbody>
</table>
<div class="section">
<h2><a name="Note_Configs_in_Ambari"></a>Note Configs in Ambari</h2>
<p>If a field is managed via ambari, you should change the field via ambari. Otherwise, upon service restarts, you may find your update overwritten.</p>
<p><a name="High_Level_Architecture"></a></p>
<h1>High Level Architecture</h1>
<p>As already pointed out in the main project README, Apache Metron is a Kappa architecture (see <a href="../../index.html#Navigating_the_Architecture">Navigating the Architecture</a>) primarily backed by Storm and Kafka. We additionally leverage:</p>
<ul>
<li>Zookeeper for dynamic configuration updates to running Storm topologies. This enables us to push updates to our Storm topologies without restarting them.</li>
<li>HBase primarily for enrichments. But we also use it to store user state for our UI&#x2019;s.</li>
<li>HDFS for long term storage. Our parsed and enriched messages land here, along with any reported exceptions or errors encountered along the way.</li>
<li>Solr and Elasticsearch (plus Kibana) for real-time access. We provide out of the box compatibility with both Solr and Elasticsearch, and custom dashboards for data exploration in Kibana.</li>
<li>Zeppelin for providing dashboards to do custom analytics.</li>
</ul>
<p>Getting data &#x201c;into&#x201d; Metron is accomplished by setting up a Kafka topic for parsers to read from. There are a variety of options, including, but not limited to:</p>
<ul>
<li><a class="externalLink" href="https://github.com/apache/metron-bro-plugin-kafka">Bro Kafka plugin</a></li>
<li><a href="../../metron-sensors/fastcapa/index.html">Fastcapa</a></li>
<li><a class="externalLink" href="https://nifi.apache.org">NiFi</a></li>
</ul>
<p><a name="Validation_Framework"></a></p>
<h1>Validation Framework</h1>
<p>Inside of the global configuration, there is a validation framework in place that enables the validation that messages coming from all parsers are valid. This is done in the form of validation plugins where assertions about fields or whole messages can be made.</p>
<p>The format for this is a <tt>fieldValidations</tt> field inside of global config. This is associated with an array of field validation objects structured like so:</p>
<ul>
<li><tt>input</tt> : An array of input fields or a single field. If this is omitted, then the whole messages is passed to the validator.</li>
<li><tt>config</tt> : A String to Object map for validation configuration. This is optional if the validation function requires no configuration.</li>
<li><tt>validation</tt> : The validation function to be used. This is one of
<ul>
<li><tt>STELLAR</tt> : Execute a Stellar Language statement. Expects the query string in the <tt>condition</tt> field of the config.</li>
<li><tt>IP</tt> : Validates that the input fields are an IP address. By default, if no configuration is set, it assumes <tt>IPV4</tt>, but you can specify the type by passing in the config by passing in <tt>type</tt> with either <tt>IPV6</tt> or <tt>IPV4</tt> or by passing in a list [<tt>IPV4</tt>,<tt>IPV6</tt>] in which case the input(s) will be validated against both.</li>
<li><tt>DOMAIN</tt> : Validates that the fields are all domains.</li>
<li><tt>EMAIL</tt> : Validates that the fields are all email addresses</li>
<li><tt>URL</tt> : Validates that the fields are all URLs</li>
<li><tt>DATE</tt> : Validates that the fields are a date. Expects <tt>format</tt> in the config.</li>
<li><tt>INTEGER</tt> : Validates that the fields are an integer. String representation of an integer is allowed.</li>
<li><tt>REGEX_MATCH</tt> : Validates that the fields match a regex. Expects <tt>pattern</tt> in the config.</li>
<li><tt>NOT_EMPTY</tt> : Validates that the fields exist and are not empty (after trimming.)</li>
</ul>
</li>
</ul>
<p><a name="Management_Utility"></a></p>
<h1>Management Utility</h1>
<p>Configurations should be stored on disk in the following structure starting at <tt>$BASE_DIR</tt>:</p>
<ul>
<li>global.json : The global config</li>
<li><tt>sensors</tt> : The subdirectory containing sensor enrichment configuration JSON (e.g. <tt>snort.json</tt>, <tt>bro.json</tt>)</li>
</ul>
<p>By default, this directory as deployed by the ansible infrastructure is at <tt>$METRON_HOME/config/zookeeper</tt></p>
<p>While the configs are stored on disk, they must be loaded into Zookeeper to be used. To this end, there is a utility program to assist in this called <tt>$METRON_HOME/bin/zk_load_config.sh</tt></p>
<p>This has the following options:</p>
<div>
<div>
<pre class="source"> -c,--config_type &lt;CONFIG_TYPE&gt; The configuration type: GLOBAL,
PARSER, ENRICHMENT, INDEXING,
PROFILER
-f,--force Force operation
-h,--help Generate Help screen
-i,--input_dir &lt;DIR&gt; The input directory containing
the configuration files named
like &quot;$source.json&quot;
-m,--mode &lt;MODE&gt; The mode of operation: DUMP,
PULL, PUSH, PATCH
-n,--config_name &lt;CONFIG_NAME&gt; The configuration name: bro,
yaf, snort, squid, etc.
-o,--output_dir &lt;DIR&gt; The output directory which will
store the JSON configuration
from Zookeeper
-pk,--patch_key &lt;PATCH_KEY&gt; The key to modify
-pm,--patch_mode &lt;PATCH_MODE&gt; One of: ADD, REMOVE - relevant
only for key/value patches,
i.e. when a patch file is not
used.
-pf,--patch_file &lt;PATCH_FILE&gt; Path to the patch file.
-pv,--patch_value &lt;PATCH_VALUE&gt; Value to use in the patch.
-z,--zk_quorum &lt;host:port,[host:port]*&gt; Zookeeper Quorum URL
(zk1:port,zk2:port,...)
</pre></div></div>
<p>Usage examples:</p>
<ul>
<li>To dump the existing configs from zookeeper on the singlenode vagrant machine: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m DUMP</tt></li>
<li>To dump the existing GLOBAL configs from zookeeper on the singlenode vagrant machine: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m DUMP -c GLOBAL</tt></li>
<li>To push the configs into zookeeper on the singlenode vagrant machine: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m PUSH -i $METRON_HOME/config/zookeeper</tt></li>
<li>To push only the GLOBAL configs into zookeeper on the singlenode vagrant machine: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m PUSH -i $METRON_HOME/config/zookeeper -c GLOBAL</tt></li>
<li>To push only the PARSER configs into zookeeper on the singlenode vagrant machine: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m PUSH -i $METRON_HOME/config/zookeeper -c PARSER</tt></li>
<li>To push only the PARSER &#x2018;bro&#x2019; configs into zookeeper on the singlenode vagrant machine: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m PUSH -i $METRON_HOME/config/zookeeper -c PARSER -n bro</tt></li>
<li>To pull all configs from zookeeper to the singlenode vagrant machine disk: <tt>$METRON_HOME/bin/zk_load_configs.sh -z node1:2181 -m PULL -o $METRON_HOME/config/zookeeper -f</tt></li>
</ul></div>
<div class="section">
<h2><a name="Patching_mechanism"></a>Patching mechanism</h2>
<p>The configuration management utility leverages a JSON patching library that conforms to <a class="externalLink" href="https://tools.ietf.org/html/rfc6902">RFC-6902 spec</a>. We&#x2019;re using the zjsonpatch library implementation from here - <a class="externalLink" href="https://github.com/flipkart-incubator/zjsonpatch">https://github.com/flipkart-incubator/zjsonpatch</a>. There are a couple options for leveraging patching. You can choose to patch the Zookeeper config via patch file:</p>
<p><tt>$METRON_HOME/bin/zk_load_configs.sh -z $ZOOKEEPER -m PATCH -c GLOBAL -pf /tmp/mypatch.txt</tt></p>
<p>or key/value pair:</p>
<p><tt>$METRON_HOME/bin/zk_load_configs.sh -z $ZOOKEEPER -m PATCH -c GLOBAL -pm ADD -pk foo -pv \&quot;\&quot;bar\&quot;\&quot;</tt></p>
<p>The options exposed via patch file are the full range of options from RFC-6902:</p>
<ul>
<li>ADD</li>
<li>REMOVE</li>
<li>REPLACE</li>
<li>MOVE</li>
<li>COPY</li>
<li>TEST</li>
</ul>
<p>whereas with key/value patching, we only current expose ADD and REMOVE. Note that ADD will function as a REPLACE when the key already exists.</p>
<div class="section">
<h3><a name="Patch_File"></a>Patch File</h3>
<p>Let&#x2019;s say we want to add a complex JSON object to our configuration with a patch file. e.g.</p>
<div>
<div>
<pre class="source">&quot;foo&quot; : {
&quot;bar&quot; : {
&quot;baz&quot; : [ &quot;bazval1&quot;, &quot;bazval2&quot; ]
}
}
</pre></div></div>
<p>We would write a patch file &#x201c;/tmp/mypatch.txt&#x201d; with contents:</p>
<div>
<div>
<pre class="source">[
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/foo&quot;,
&quot;value&quot;: { &quot;bar&quot; : { &quot;baz&quot; : [ &quot;bazval1&quot;, &quot;bazval2&quot; ] } }
}
]
</pre></div></div>
<p>And submit via zk_load_configs as follows:</p>
<div>
<div>
<pre class="source"> $METRON_HOME/bin/zk_load_configs.sh -z $ZOOKEEPER -m PATCH -c GLOBAL -pf /tmp/mypatch.txt
</pre></div></div>
</div>
<div class="section">
<h3><a name="Patch_Key.2FValue"></a>Patch Key/Value</h3>
<p>Now let&#x2019;s try the same without using a patch file, instead using the patch_key and patch_value options right from the command line utility. This would like like the following.</p>
<div>
<div>
<pre class="source">$METRON_HOME/bin/zk_load_configs.sh -z $ZOOKEEPER -m PATCH -c GLOBAL -pm ADD -pk &quot;/foo&quot; -pv &quot;{ \&quot;bar\&quot; : { \&quot;baz\&quot; : [ \&quot;bazval1\&quot;, \&quot;bazval2\&quot; ] } }&quot;
</pre></div></div>
</div>
<div class="section">
<h3><a name="Applying_Multiple_Patches"></a>Applying Multiple Patches</h3>
<p>Applying multiple patches is also pretty straightforward. You can achieve this in a single command using patch files, or simply execute multiple commands in sequence using the patch_key/value approach.</p>
<p>Let&#x2019;s say we wanted to add the following to our global config:</p>
<div>
<div>
<pre class="source">&quot;apache&quot; : &quot;metron&quot;,
&quot;is&quot; : &quot;the best&quot;,
&quot;streaming&quot; : &quot;analytics platform&quot;
</pre></div></div>
<p>and remove the /foo key from the previous example.</p>
<p>Create a patch file /tmp/mypatch.txt with four separate patch operations.</p>
<div>
<div>
<pre class="source">[
{
&quot;op&quot;: &quot;remove&quot;,
&quot;path&quot;: &quot;/foo&quot;
},
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/apache&quot;,
&quot;value&quot;: &quot;metron&quot;
},
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/is&quot;,
&quot;value&quot;: &quot;the best&quot;
},
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/streaming&quot;,
&quot;value&quot;: &quot;analytics platform&quot;
}
]
</pre></div></div>
<p>Now submit again and you should see a Global config with the &#x201c;foo&#x201d; key removed and three new keys added.</p>
<div>
<div>
<pre class="source"> $METRON_HOME/bin/zk_load_configs.sh -z $ZOOKEEPER -m PATCH -c GLOBAL -pf /tmp/mypatch.txt
</pre></div></div>
</div>
<div class="section">
<h3><a name="Notes_On_Patching"></a>Notes On Patching</h3>
<p>For any given patch key, the last/leaf node in the key&#x2019;s parent <i>must</i> exist, otherwise an exception will be thrown. For example, if you want to add the following:</p>
<div>
<div>
<pre class="source">&quot;foo&quot;: {
&quot;bar&quot;: &quot;baz&quot;
}
</pre></div></div>
<p>It is not sufficient to use /foo/bar as a key if foo does not already exist. You would either need to incrementally build the JSON and make this a two step process</p>
<div>
<div>
<pre class="source">[
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/foo&quot;,
&quot;value&quot;: { }
},
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/foo/bar&quot;,
&quot;value&quot;: &quot;baz&quot;
}
]
</pre></div></div>
<p>Or provide the value as a complete JSON object.</p>
<div>
<div>
<pre class="source">[
{
&quot;op&quot;: &quot;add&quot;,
&quot;path&quot;: &quot;/foo&quot;,
&quot;value&quot;: { &quot;bar&quot; : &quot;baz&quot; }
}
]
</pre></div></div>
<p>The REMOVE operation is idempotent. Running the remove command on the same key multiple times will not fail once the key has been removed.</p>
<p><a name="Topology_Errors"></a></p>
<h1>Topology Errors</h1>
<p>Errors generated in Metron topologies are transformed into JSON format and follow this structure:</p>
<div>
<div>
<pre class="source">{
&quot;exception&quot;: &quot;java.lang.IllegalStateException: Unable to parse Message: ...&quot;,
&quot;failed_sensor_type&quot;: &quot;bro&quot;,
&quot;stack&quot;: &quot;java.lang.IllegalStateException: Unable to parse Message: ...&quot;,
&quot;hostname&quot;: &quot;node1&quot;,
&quot;source:type&quot;: &quot;error&quot;,
&quot;raw_message&quot;: &quot;{\&quot;http\&quot;: {\&quot;ts\&quot;:1488809627.000000.31915,\&quot;uid\&quot;:\&quot;C9JpSd2vFAWo3mXKz1\&quot;, ...&quot;,
&quot;error_hash&quot;: &quot;f7baf053f2d3c801a01d196f40f3468e87eea81788b2567423030100865c5061&quot;,
&quot;error_type&quot;: &quot;parser_error&quot;,
&quot;message&quot;: &quot;Unable to parse Message: {\&quot;http\&quot;: {\&quot;ts\&quot;:1488809627.000000.31915,\&quot;uid\&quot;:\&quot;C9JpSd2vFAWo3mXKz1\&quot;, ...&quot;,
&quot;timestamp&quot;: 1488809630698,
&quot;guid&quot;: &quot;bf9fb8d1-2507-4a41-a5b2-42f75f6ddc63&quot;
}
</pre></div></div>
<p>Each topology can be configured to send error messages to a specific Kafka topic. The parser topologies retrieve this setting from the the <tt>parser.error.topic</tt> setting in the global config:</p>
<div>
<div>
<pre class="source">{
&quot;es.clustername&quot;: &quot;metron&quot;,
&quot;es.ip&quot;: &quot;node1&quot;,
&quot;es.port&quot;: &quot;9300&quot;,
&quot;es.date.format&quot;: &quot;yyyy.MM.dd.HH&quot;,
&quot;parser.error.topic&quot;: &quot;indexing&quot;
}
</pre></div></div>
<p>Error topics for enrichment and threat intel errors are passed into the enrichment topology as flux properties named <tt>enrichment.error.topic</tt> and <tt>threat.intel.error.topic</tt>. These properties can be found in <tt>$METRON_HOME/config/enrichment.properties</tt>.</p>
<p>The error topic for indexing errors is passed into the indexing topology as a flux property named <tt>index.error.topic</tt>. This property can be found in either <tt>$METRON_HOME/config/elasticsearch.properties</tt> or <tt>$METRON_HOME/config/solr.properties</tt> depending on the search engine selected.</p>
<p>By default all error messages are sent to the <tt>indexing</tt> topic so that they are indexed and archived, just like other messages. The indexing config for error messages can be found at <tt>$METRON_HOME/config/zookeeper/indexing/error.json</tt>.</p>
<p><a name="Performance_Logging"></a></p>
<h1>Performance Logging</h1>
<p>The PerformanceLogger class provides functionality that enables developers to debug performance issues. Basic usage looks like the following:</p>
<div>
<div>
<pre class="source">// create a simple inner performance class to use for logger instantiation
public static class Perf {}
// instantiation
PerformnanceLogger perfLog = new PerformanceLogger(() -&gt; getConfigurations().getGlobalConfig(), Perf.class.getName());
// marking a start time
perfLog.mark(&quot;mark1&quot;);
// ...do some high performance stuff...
// log the elapsed time
perfLog.log(&quot;mark1&quot;, &quot;My high performance stuff is very performant&quot;);
// log no additional message, just the basics
perfLog.log(&quot;mark1&quot;);
</pre></div></div>
<p>The logger maintains a Map&lt;String, Long&gt; of named markers that correspond to start times. Calling mark() performs a put on the underlying timing store. Output includes the mark name, elapsed time in nanoseconds, as well as any custom messaging you provide. A sample log would look like the following:</p>
<div>
<div>
<pre class="source">[DEBUG] markName=execute,time(ns)=121411,message=key=7a8dbe44-4cb9-4db2-9d04-7632f543b56c, elapsed time to run execute
</pre></div></div>
<p><b>Configuration</b></p>
<p>The first argument to the logger is a java.util.function.Supplier&lt;Map&lt;String, Object&gt;&gt;. The offers flexibility in being able to provide multiple configuration &#x201c;suppliers&#x201d; depending on your individual usage requirements. The example above, taken from org.apache.metron.enrichment.bolt.GenericEnrichmentBolt, leverages the global config to dymanically provide configuration from Zookeeper. Any updates to the global config via Zookeeper are reflected live at runtime. Currently, the PerformanceLogger supports the following options:</p>
<table border="0" class="table table-striped">
<thead>
<tr class="a">
<th>Property Name </th>
<th>Type </th>
<th>Valid Values </th></tr>
</thead><tbody>
<tr class="b">
<td>performance.logging.percent.records </td>
<td>Integer </td>
<td>0-100 </td></tr>
</tbody>
</table>
<p><b>Other Usage Details</b></p>
<p>You can also provide your own format String and provide arguments that will be used when formatting that String. This code avoids expensive String concatenation by only formatting when debugging is enabled. For more complex arguments, e.g. JSON serialization, we expose an isDebugEnabled() method.</p>
<div>
<div>
<pre class="source">// log with format String and single argument
perfLog.log(&quot;join-message&quot;, &quot;key={}, elapsed time to join messages&quot;, key);
// check if debugging is enabled for the performance logger to avoid more expensive operations
if (perfLog.isDebugEnabled()) {
perfLog.log(&quot;join-message&quot;, &quot;key={}, elapsed time to join messages, message={}&quot;, key, rawMessage.toJSONString());
}
</pre></div></div>
<p><b>Side Effects</b></p>
<p>Calling the mark() method multiple times simply resets the start time to the current nano time. Calling log() with a non-existent mark name will log 0 ns elapsed time with a warning indicating that log has been invoked for a mark name that does not exist. The class is not thread-safe and makes no attempt at keeping multiple threads from modifying the same markers.</p>
<p><a name="Metron_Debugging"></a></p>
<h1>Metron Debugging</h1>
<p>A Python script is provided for gathering information useful in debugging your Metron cluster. Run from the node that has Metron installed on it. All options listed below are required.</p>
<p><i>Note:</i> Be aware that no anonymization/scrubbing is performed on the captured configuration details.</p>
<div>
<div>
<pre class="source"># $METRON_HOME/bin/cluster_info.py -h
Usage: cluster_info.py [options]
Options:
-h, --help show this help message and exit
-a HOST:PORT, --ambari-host=HOST:PORT
Connect to Ambari via the supplied host:port
-c NAME, --cluster-name=NAME
Name of cluster in Ambari to retrieve info for
-o DIRECTORY, --out-dir=DIRECTORY
Write debugging data to specified root directory
-s HOST:PORT, --storm-host=HOST:PORT
Connect to Storm via the supplied host:port
-b HOST1:PORT,HOST2:PORT, --broker_list=HOST1:PORT,HOST2:PORT
Connect to Kafka via the supplied comma-delimited
host:port list
-z HOST1:PORT,HOST2:PORT, --zookeeper_quorum=HOST1:PORT,HOST2:PORT
Connect to Zookeeper via the supplied comma-delimited
host:port quorum list
-m DIRECTORY, --metron_home=DIRECTORY
Metron home directory
-p DIRECTORY, --hdp_home=DIRECTORY
HDP home directory
</pre></div></div></div></div>
</div>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
© 2015-2016 The Apache Software Foundation. Apache Metron, Metron, Apache, the Apache feather logo,
and the Apache Metron project logo are trademarks of The Apache Software Foundation.
</div>
</div>
</footer>
</body>
</html>