
<div class="contentWrapper help">

    <div class="pageTitle">
        <h1>Help manual</h1>
    </div>

    <?php
        $this->load->view('directives/directive_onboardwizard.php');
    $this->load->view( 'directives/tour_guide.php' );
    ?>
    <p class="margin-bottom">
        <a href="javascript:void(0)" onclick="showWelcome()">Take the welcome tour again.</a>
    </p>

    <ul class="contentTable">
        <li><h3>Contents</h3></li>
        <li><a href="#hosts-grouping-help">Grouping of Hosts</a></li>
        <li><a href="#dashboard-help">Dashboards</a></li>
        <li><a href="#hosts-help">Hosts</a></li>
        <li><a href="#vcs">VCS deployments</a></li>
        <li><a href="#monitoring-help">Measurements</a></li>
        <li><a href="#sql_reports">Reports</a></li>
        <li><a href="#sql_tips">SQL tips</a></li>
    </ul>

    <h2 id="hosts-grouping-help">Grouping of Hosts</h2>

    <p>CFEngine allows for arbitrary grouping of hosts based on specified criteria. If you are writing your own policy, you are able to set classes on hosts which can be used in the Mission Portal. If you are not, you can still use pre-defined groups that CFEngine discovers automatically in your environment.</p>

    <p>CFEngine's Mission Portal comes with a pre-defined host grouping based on operating systems used in your environment. The same grouping is used for the menu on the left of the Hosts App, the data-filtering inside the Reports App.</p>

    <p>You can also define your own groups and sub-groups. As part of the menu inside the Hosts App, you will find the option to add a new grouping. Here you can organize your hosts in whichever way you need by combining different classes. You can then share your custom grouping within your team and organization (this needs special access rights).</p>


    <br />
    <h2  id="dashboard-help">Dashboards</h2>

    <p>A dashboard contains informative widgets that you can customize to create alerts that are important to you. You can create multiple dashboards, each with its own set of widgets. You may also choose to share a dashboard with other users - this means that others using Mission Portal will be able to view your dashboard, but they will be unable to make any changes to it or any of its widgets.</p>

    <p>There are two types of widget you can add to your dashboard: Changes and Alerts.

    <h3>Changes</h3>

    <p>The Changes widget shows at a glance the number of changes that have been made to your infrastructure by CFEngine during the past seven days. By clicking on the widget you can see the full report of changes in the <a href="#changes">Changes reporting interface</a>. Clicking on a single day will show you a report for that day only.</p>


    <h3>Alerts and conditions</h3>

    <p>Alerts can have three different severities: low, medium and high. These are represented by rings in yellow, orange and red respectively, along with the percentage of hosts alerts have triggered on. Hovering over the widget will show all information in a convenient list.</p>

    <p>Alerts trigger based on custom defined conditions. Currently, CFEngine supports alerts for policy, iventory, software updates, custom SQL. To create an alert, you have to specify its severity, define the condition for triggering, and select a group of hosts to apply the condition to.</p>

    <p>Conditions set the rules for an alert. Once a condition is met on a specified set of hosts, the alert will trigger. They are stored independently from alerts and host groups. It is possible to use the same condition for different alerts by simply selecting the condition you'd like to re-use from the condition dropdown menu when defining a new alert. Deleting an alert will not delete the condition attached to it.</p>

    <h4>Which kinds of conditions exist?</h4>

    <ul>
        <li><strong>Policy</strong><br>Policy conditions trigger alerts based on CFEngine policy compliance status. They can be set on bundles, promisees, and promises. If nothing is specified, they will trigger alerts for all policy.</li>
        <li><strong>Inventory</strong><br>Inventory conditions trigger alerts for inventory attributes. These attributes correspond to the ones found in inventory reports. </li>
        <li><strong>Software updates</strong><br>Software update conditions trigger alerts based on packages available for update in the repository. They can be set either for a specific version or trigger on the latest version available. If neither a package nor a version is specified, they will trigger alerts for any update.</li>
        <li><strong>Custom SQL</strong><br>Custom SQL conditions trigger alerts based on an SQL query. The SQL query must returns at least one column - hostkey.</li>
    </ul>

    <p>All alert state changes, e.g. from OK to triggered, are logged to the Event log.</p>

    <h3>Reporting on alerts</h3>

    <p>Once an alert has been triggered, you can access the corresponding data via the alert overview. You can either report on a single or on all affected hosts at the same time. All reports accessed via the dashboard benefit from all other report features such as sending them as emails on a defined schedule.</p>

    <h3>Multiple dashboards</h3>
    <p></p>

    <br />
    <h2 id="hosts-help">Hosts</h2>

    <h3>Overview</h3>

    <p>CFEngine collects data on promise compliance. Hosts are then sorted into three different groups: erroneous, fully compliant, and non-healthy.</p>

    <ul>
    	<li>A host is considered erroneous if less than 100% of its promises were kept.</li>
    	<li>A host is considered fully compliant if 100% of its promises were kept.</li>
    	<li>A host is considered non-healthy
            <ul>
               <li>if the hub is not able to connect to it within a set time interval (unreachable host). The time interval can be set in Mission Portal Settings.</li>
    	       <li>or if the policy has not been executed for the last three runs. This could be caused by cf-execd not running on the host (scheduling deviation) or an error in policy that stops its execution. The hub is still able to contact the host, but it will return stale data because of this deviation.</li>
            </ul>
    </ul>

    <p>The number of non-healthy hosts is displayed in the health indicator in the menu bar on the top. From there, you are able to access more information on either condition mentioned above seperately.

    <p>You can look at a specific sub-set of your hosts by selecting a category from the menu on the left.</p>

    <a href="javascript:void(0)" id="info"></a>
    <br />
    <h3>Host Information</h3>

    <p>Here you will find extensive information on single hosts that CFEngine detects automatically in your environment. Since this is data gathered per host, you need to select a single host from the menu on the left first. This information is accessible from everywhere inside the Mission Portal where a host identifier is presented as a link.</p>

    <br />
    <h2 id="vcs" >Enable VCS deployments in the versioned update.cf</h2>

    <p>In the file <code>update_def.cf</code> under a version-specific
        subdirectory of <code>controls/</code> in your version-controlled
        masterfiles, change </p>

    <pre><code>#&quot;cfengine_internal_masterfiles_update&quot; expression =&gt; &quot;enterprise.!(cfengine_3_4|cfengine_3_5)&quot;;
&quot;cfengine_internal_masterfiles_update&quot; expression =&gt; &quot;!any&quot;;
</code></pre>

    <p>to</p>

    <pre><code>&quot;cfengine_internal_masterfiles_update&quot; expression =&gt; &quot;enterprise.!(cfengine_3_4|cfengine_3_5)&quot;;
#&quot;cfengine_internal_masterfiles_update&quot; expression =&gt; &quot;!any&quot;;
</code></pre>

    <p>This is simply commenting out one line and uncommenting another.</p>

    <p>Remember that you need to commit and push these changes to the
        repository, so that they are picked up when the policies are
        deployed from it. In your checked out <code>masterfiles</code> git
        repository, run these commands:</p>

    <pre><code>git add update.cf
git commit -m &#39;Enabled auto-policy updates&#39;
git push origin master
</code></pre>

    <p>Now you need to do the first-time deployment, whereupon this
        new <code>update.cf</code> and the rest of your versioned
        masterfiles will overwrite <code>/var/cfengine/masterfiles</code>.
        We made that easy too, using standard CFEngine tools. Exit the
        <code>cfapache</code> account and run the following command as
        <code>root</code> on your hub:</p>

    <pre><code>cf-agent -Dcfengine_internal_masterfiles_update -f update.cf
</code></pre>

    <p>Easy, right?  You&#39;re done, from now on every time
        <code>update.cf</code> is run (by default, every 5 minutes) it
        will check out the repository and branch you configured in the
        Mission Portal VCS integration panel.</p>
    <br />

    <h2 id="monitoring-help">Measurements</h2>

    <p>Measurements allows you to get an overview of your hosts over time.</p>

    <p>You can reduce the number of graphs displayed by selecting a sub-set of hosts from the menu on the left.</p>

    <h3>Enabling collection of monitoring data</h3>
    <p>The <code>report_data_select</code> attribute in your masterfiles policy controls which monitoring data is collected from your hub and nodes.</p> See the Masterfiles Policy Framework documentation on <a target="_blank" href="https://docs.cfengine.com/docs/<?= CFE_MAJOR_MINOR_VERSION ?>/reference-masterfiles-policy-framework.html#configure-enterprise-measurement-monitoring-collection">configuring monitoring metrics to be collected</a>.

    <br />
    <h2 id="sql_reports">Reports</h2>

    <p>CFEngine collects a large amount of data. The Mission Portal makes this data available via pre-defined queries, inventory reports, and through a query builder that lets you define your own custom queries. You can save all queries for later use, and schedule reports for specified times.</p>

    <a href="javascript:void(0)" id="inventory"></a>
    <h3>Inventory</h3>

    <p>The inventory reports interface allows for quick reporting on out-of-the-box attributes. You can reduce the amount of data or find specific information by filtering on attributes and host groups. Filtering is independent from the data presented in the results table: you can filter on attributes without them being presented in the table of results.</p>

    <p>To add more columns to your report, you simply need to select items from the drop down list. The list items correspond to the ones used to filter on attributes with the single exception of <em>software installed</em>. Reporting on <strong>all</strong> software installed is beyond the scope of inventory reports.</p>

    <a href="javascript:void(0)" id="custom_attributes"></a>
    <h4>Custom inventory attributes</h4>

    <p>You can add your own custom attributes, like Environment or Role, by leveraging any variable or class in your CFEngine policy (masterfiles).
    To do this, simply add the "inventory" and "attribute_name=MyAttributeName" meta tags to that class or variable.</p>

    <p>For example, use the following to make a new class-based inventory attribute called "Roles".</p>

    <pre><code>classes:

     "web_server"
       or   => { "host1", "host2" },
       meta => { "inventory", "attribute_name=Roles" };

     "db_server"
       or   => { "host1", "host3" },
       meta => { "inventory", "attribute_name=Roles" };
    </code></pre>

    <p>You can also make inventory attributes out of variables in the same way:</p>

    <pre><code>vars:

     "system_serial_number"
       string => execresult("dmidecode -s system-serial-number", "useshell"),
       meta => { "inventory", "attribute_name=System serial number" };
    </code></pre>

    <p>This would make a new variable-based inventory attribute called "System serial number". All custom attributes will appear under the category &quot;User defined&quot; once CFEngine has collected data from the relevant hosts.</p>

    <a href="javascript:void(0)" id="changes"></a>
    <h3>Changes reporting</h3>

    <p>The changes reporting interface allows you to see the changes made to the infrastructure by CFEngine in the past seven days. By default, the data is sorted with the most recent changes first. Similar to the inventory reports, you can narrow the data down by filtering on attributes and host groups - and in addition you can use the date range picker to select a specific time frame for your report.</p>

    <p>A changes widget, which shows a chart of recent changes made by CFEngine, can also be added to your dashboard. <a href="#dashboard-help">Read more about dashboards</a>.</p>

    <h3>Filtering of results</h3>

    <p>You can narrow the amount of hosts to be queried with the help of filters above the displayed table. These filters are based on the same grouping you can find everywhere else. Additionally, filtering on attributes is available for inventory and changes reports.</p>


    <h3>Query Builder</h3>

    <p>If you are familiar with SQL syntax you have the option to input your query into the interface directly. Make sure to take a look at the database schema. <strong>Please note:</strong> manual entries in the query field at the bottom of the query builder will invalidate all field selections and filters above, and vice-versa.</p>

    <p>Users not familiar with SQL syntax can easily create their own custom reports in this interface.</p>

    <ul>
    	<li>Tables - Select the data tables you want include in your report first.</li>
    	<li>Fields - Define your table columns based on your selection above.</li>
    	<li>Filters - Filter your results.</li>
    	<li>Sort - Sort your results.</li>
    	<li>Limit - Limit the number of entries in your report. This is a recommended practice for testing your query.</li>
    	<li>Show me the query - View and edit the SQL query directly. Please note, that editing the query directly here will invalidate your choices in the query builder interface, and changing your selections there will override your SQL query.</li>
    </ul>

    <p>Please note, that queries on log tables without LIMIT may return a lot of records, which might cause your browser to crash or to throw a <b>"Write error"</b>.</p>
    <p><a target="_blank" href="https://docs.cfengine.com/docs/<?= htmlspecialchars(CFE_MAJOR_MINOR_VERSION)?>/reference-enterprise-api-ref-sql-schema.html">See Database Schema.</a></p>

    <br />
    <h2 id="sql_tips">SQL tips</h2>
    <p>This is a brief tutorial on SQL syntax tailored to the Mission Portal's SQL reports, for detailed information please take a look at <a href="http://www.postgresql.org/docs/10/static/index.html">the PostgreSQL website.</a></p>

    <p>Please note, we only provide <b>readonly</b> access.</p>
    <br />
    <h3>SELECT syntax</h3>
    <p>
    <pre class="prettyprint lang-sql">
    SELECT
        [ALL | DISTINCT  ]
    FROM table_references
        [WHERE where_condition]
        [GROUP BY {col_name | expr }
          [ASC | DESC]
        [HAVING where_condition]
        [ORDER BY {col_name | expr }
          [ASC | DESC], ...]
        [LIMIT {[offset,] row_count}]
    </pre>
    </p>
    <br />

    <h3>Sample SQL queries</h3>
    <ol>
        <li>Return all columns from table
            <p>
            <pre class="prettyprint lang-sql">SELECT * FROM table_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT * FROM Hosts</pre>
            </p>
        </li>

        <li>Return specific column from table
            <p>
            <pre class="prettyprint lang-sql">SELECT column_name FROM table_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT HostName FROM Hosts</pre>
            </p>
        </li>

        <li>Return number of rows
            <p>
            <pre class="prettyprint lang-sql">SELECT COUNT(*) FROM table_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT COUNT(*) FROM FileChanges</pre>
            </p>
        </li>

        <li>Return unique values of column (<em>DISTINCT</em>)
            <p>
            <pre class="prettyprint lang-sql">SELECT DISTINCT column_name FROM table_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT DISTINCT HostName FROM Hosts</pre>
            </p>
        </li>

        <li>Return rows that match condition (<em>WHERE</em>)
            <p>
            <pre class="prettyprint lang-sql">SELECT * FROM table_name WHERE condition</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT * FROM FileChangesLog  WHERE FileName = '/etc/passwd'</pre>
            </p>
        </li>

        <li>Search for a specified pattern in a column (<em>LIKE or ILIKE for case insensitive</em>)
            <p>
                A <b>"%"</b> sign can be used to define wildcards (missing letters in the pattern) both before and after the pattern.<br />
                A <b>"?"</b> sign can be used to define a single missing letter both before and after the pattern.
            <pre class="prettyprint lang-sql">SELECT * FROM table_name WHERE file_name ILIKE "%example%"</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT * FROM Host WHERE HostName ILIKE "ubu%"</pre>
            </p>
        </li>


        <li>Join two tables and return all columns (<em><type> JOIN</em>)
            <p>
            <pre class="prettyprint lang-sql">SELECT * FROM table_name1 INNER JOIN table_name2 ON table_name1.field_name = table2.field_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT * FROM FileChangesLog INNER JOIN Hosts ON Hosts.HostKey = FileChanges.HostKey</pre>
            </p>
        </li>

        <li>Return rows grouped by value (<em>GROUP BY</em>)
            <p>
            <pre class="prettyprint lang-sql">SELECT * FROM table_name GROUP BY field_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT PromiseExecutions.PromiseHandle, count(*) as c FROM PromiseExecutions GROUP BY PromiseExecutions.PromiseHandle</pre>
            </p>
        </li>


        <li>Return all rows ordered by column (<em>ORDER BY [ASC | DESC]</em>)
            <p>
            <pre class="prettyprint lang-sql">SELECT * FROM table_name ORDER BY column_name</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT * FROM Host ORDER BY HostName</pre>
            </p>
        </li>

        <li>Limit result, return first 30 rows after row 10 (<em>LIMIT</em>)
            <p>
            <pre class="prettyprint lang-sql">SELECT * FROM table_name LIMIT 10, 30</pre>
            for example:
            <pre class="prettyprint lang-sql">SELECT * FROM Host LIMIT 10, 30</pre>
            </p>
        </li>

        <li>Complex Query example
            <p>
    <pre class="prettyprint lang-sql">SELECT Hosts.HostName AS "Host name",
	Hosts.IPAddress AS "IP address",
	count(SoftwareUpdates.hostkey)
	FROM SoftwareUpdates INNER JOIN Hosts ON Hosts.HostKey = SoftwareUpdates.HostKey
GROUP BY Hosts.hostkey, Hosts.HostName, Hosts.IPAddress , SoftwareUpdates.hostkey</pre>
            </p>
        </li>
    </ol>
    <br />
    <h3>Operators</h3>
    <p>PostgreSQL understands the following binary operators, ordered from highest to lowest precedence:</p>
    <table class="table table-bordered" style="width: 600px;">
        <colgroup><col>
        <col>
        <col>

        </colgroup><thead>
          <tr>
            <th>Operator/Element</th>

            <th>Associativity</th>

            <th>Description</th>
          </tr>
        </thead>

        <tbody>
          <tr>
            <td>.</td>

            <td>left</td>

            <td>table/column name separator</td>
          </tr>

          <tr>
            <td>::</td>

            <td>left</td>

            <td><span class="PRODUCTNAME">PostgreSQL</span>-style
            typecast</td>
          </tr>

          <tr>
            <td>[ ]</td>

            <td>left</td>

            <td>array element selection</td>
          </tr>

          <tr>
            <td>+ -</td>

            <td>right</td>

            <td>unary plus, unary minus</td>
          </tr>

          <tr>
            <td>^</td>

            <td>left</td>

            <td>exponentiation</td>
          </tr>

          <tr>
            <td>* /
            %</td>

            <td>left</td>

            <td>multiplication, division, modulo</td>
          </tr>

          <tr>
            <td>+ -</td>

            <td>left</td>

            <td>addition, subtraction</td>
          </tr>

          <tr>
            <td>IS</td>

            <td>&nbsp;</td>

            <td>IS TRUE, IS FALSE, IS NULL, etc</td>
          </tr>

          <tr>
            <td>ISNULL</td>

            <td>&nbsp;</td>

            <td>test for null</td>
          </tr>

          <tr>
            <td>NOTNULL</td>

            <td>&nbsp;</td>

            <td>test for not null</td>
          </tr>

          <tr>
            <td>(any other)</td>

            <td>left</td>

            <td>all other native and user-defined operators</td>
          </tr>

          <tr>
            <td>IN</td>

            <td>&nbsp;</td>

            <td>set membership</td>
          </tr>

          <tr>
            <td>BETWEEN</td>

            <td>&nbsp;</td>

            <td>range containment</td>
          </tr>

          <tr>
            <td>OVERLAPS</td>

            <td>&nbsp;</td>

            <td>time interval overlap</td>
          </tr>

          <tr>
            <td>LIKE ILIKE SIMILAR</td>

            <td>&nbsp;</td>

            <td>string pattern matching</td>
          </tr>

          <tr>
            <td>&lt; &gt;</td>

            <td>&nbsp;</td>

            <td>less than, greater than</td>
          </tr>

          <tr>
            <td>=</td>

            <td>right</td>

            <td>equality, assignment</td>
          </tr>

          <tr>
            <td>NOT</td>

            <td>right</td>

            <td>logical negation</td>
          </tr>

          <tr>
            <td>AND</td>

            <td>left</td>

            <td>logical conjunction</td>
          </tr>

          <tr>
            <td>OR</td>

            <td>left</td>

            <td>logical disjunction</td>
          </tr>
        </tbody>
      </table>
    <p>You can find more details in the <a href="http://www.postgresql.org/docs/10/interactive/sql-syntax-lexical.html#SQL-PRECEDENCE-TABLE">official documentation</a>.</p>
    <p>To compare values in the right way you have to cast them into the same format, for example:</p>
    <pre>SELECT CAST(field_name AS type)</pre>
    <p>allowed types: TEXT ,  REAL (float), INTEGER , NUMERIC, for example:</p>
    <p>
    <pre class="prettyprint lang-sql">
    SELECT Hosts.HostName, Variables.VariableValue as originalValue, Variables.VariableName, cast(Variables.VariableValue AS REAL)  as CPU_LOAD
    FROM Variables INNER JOIN Hosts ON Hosts.HostKey = Variables.HostKey
    WHERE Variables.VariableName LIKE '%cpu%' AND  (CASE WHEN Variables.VariableValue = '' THEN NULL ELSE cast(Variables.VariableValue AS REAL ) END) >= 1
    LIMIT 100
    </pre>
    </p>
    <p><b>Note:</b> In this example we check if a value is an empty string, and then cast it to NULL, or otherwise cast it to REAL.</p>
    <br />
    <h3>Aggregate Functions</h3>
    <table class="table">
        <tbody>
            <tr>
                <td width="120">
                    avg(<em>X</em>)</td>
                <td>
                    The avg() function
                    returns the average value of all non-NULL <em>X</em> within a
                    group.
                </td>
            </tr>
            <tr>
                <td>
                    count(<em>X</em>)<br><br>count(*)
                </td>
                <td>
                    The count(X) function returns
                    a count of the number of times
                    that <em>X</em> is not NULL in a group.  The count(*) function
                    (with no arguments) returns the total number of rows in the group.
                </td>
            </tr>
            <tr>
                <td>
                    max(<em>X</em>)
                </td>
                <td>
                    The max() aggregate function
                    returns the maximum value of all values in the group.
                    The maximum value is the value that would be returned last in an
                    ORDER BY on the same column. Aggregate max() returns NULL
                    if and only if there are no non-NULL values in the group.
                </td>
            </tr>
            <tr>
                <td>
                    min(<em>X</em>)
                </td>
                <td>
                    The min() aggregate function returns the minimum non-NULL value of all values in the group.
                </td>
            </tr>
            <tr>
                <td>
                    sum(<em>X</em>)
                </td>
                <td>
                    The sum()  aggregate functions
                    return sum of all non-NULL values in the group.
                    If there are no non-NULL input rows then sum() returns
                    NULL</td>
            </tr>
        </tbody>
    </table>


    <h3>Date and time</h3>
    <p>The type for all "timestamp" fields in database is set to timestamps with time zones (timestamptz). The time zone is defined by the hub time zone (system locale).</p>
</div>


<script type="text/javascript">
$(document).ready(function() {
    prettyPrint();
});

function showWelcome() {
    var options = {
        showCancel:true,
        keyboard:true,
        buttons:{
            cancelText:'Close',
            nextText:'Next',
            submitText:'Get started!'
        }
    };

    var el = $('#wizard-modal');
    var wizard = el.wizard(options);
    wizard.show();

     wizard.on('submit', function() {
        wizard.close();
    });

    $('#showAgain').hide();
}

function showTourModal() {
    tourGuide.init().restart();
    window.localStorage.setItem('tourStarted', 'true')
    window.localStorage.setItem('tourPaused', 'false')
}
</script>
