<?php
if ( ! defined( 'BASEPATH' ) ) {
    exit( 'No direct script access allowed' );
}

$cf_version_array       = explode( ".", CFE_CORE_VERSION );
$cf_major_minor_version = "$cf_version_array[0]" . "." . "$cf_version_array[1]";

$firewall = [
    'question' => 'Firewall, esp on host',
    'response' => 'By default hubs collect from each host by connecting to port 5308. Verify that the hub can make connections to the remote agent.

Perform a manual delta collection to confirm your ability to connect to port 5308 on the remote host.

<pre>cf-hub --query delta --query-host &laquo;agent ip or hostname&raquo; --verbose</pre>
If you are unable to open the port so that the hub can imitate the report collection switch to <a href="https://docs.cfengine.com/docs/' . $cf_major_minor_version . '/reference-masterfiles-policy-framework.html#enable-client-initiated-reporting">client initiated reporting.</a> '
];

$tooFewLicense = [
    'question' => 'Too few licenses',
    'response' => 'CFEngine Enterprise will only collect for up to the licensed number of hosts. If more hosts are bootstrapped to a hub than it is licensed for some host (non-deterministic) will not be collected from and an error will be emitted by cf-hub. <br />
<pre>CFEngine(hub) 882 hosts are connected to this hub, but it is only licensed to support 800 clients. Please contact CFEngine (http://www.cfengine.com) for more licenses</pre>
Contact your account manager or sales@northern.tech to expand your license agreement.

'
];

$communityEdition = [
    'question' => 'Community edition',
    'response' => 'Only Enterprise agents are capable of reporting outcomes to an Enterprise hub.

If a community agent is bootstrapped to an enterprise hub you will find connections from it in the lastseen database, but report collection will never succeed. Hosts are only shown in Mission Portal after they have been collected from.

Verify that the host not reporting is running CFEngine Enterprise. cf-promises --version should show CFEngine Enterprise.

<pre>cf-promises --version</pre>
'
];

$accessPolicy = [
    'question' => 'Access policy',
    'response' => 'CFEngine requires an access promise in order to access any resources provided by cf-serverd. By default known policy servers (def.policy_servers) are allowed to query for enterprise reports.

cf-hub will error if access is not allowed.

<pre>error: Abort transmission: got " Unspecified server refusal (see verbose server output)" from 192.168.33.2</pre>
Inspect the verbose logs from cf-serverd on the agent to see access denials.

 <pre>b4e497cb8155501b492e4d: Client is TRUSTED, public key MATCHES stored one.
   info: 192.168.33.2> access denied to query: delta 1523627006 1523627358
verbose: 192.168.33.2> REFUSAL to (user=root,ip=192.168.33.2) of request: QUERY delta 1523627006 1523627358
verbose: 192.168.33.2> Remote peer terminated TLS session (SSL_read)
   info: 192.168.33.2> Closing connection, terminating thread</pre>'
];


$notAbleToCollect = [
    'question' => 'Not able to complete collection (log from diagnostics table)',
    'response' => 'cf-hub has a finite amount of time to complete collection of all reports from a host before the connection is terminated.

Perform a manual delta collection.

<pre>cf-hub --query delta --query-host &laquo;agent ip or hostname&raquo; -v</pre>
If that fails perform a manual rebase collection.

<pre>cf-hub --query rebase --query-host &laquo;agent ip or hostname&raquo; -v</pre>
If the problem reoccurs frequently contact support and consider setting a low threshold for <a href="https://docs.cfengine.com/docs/' . $cf_major_minor_version . '/reference-masterfiles-policy-framework.html#adjust-the-maximum-amount-of-client-side-report-data-to-retain-cfengine-enterprise">def.max_client_history_size</a>.'
];

$hostsOffline        = [
    'question' => 'Host offline/lost network',
    'response' => 'When a host is offline or otherwise unreachable via the network it will not be able to be collected from.
                   Try to ping and traceroute the host from the hub.'
];
$hostsDecommissioned = [
    'question' => 'Host decommissioned/re-provisioned',
    'response' => 'When a host is decommissioned it should be removed from the CFEngine Hub or it will begin to report health issues. Similarly, if a host is re-provisioned and it\'s identity ( $(sys.workdir)/ppkeys/localhost
{pub,priv}
) is not preserved the old identity should be removed or the host will report health issues.
Verify that the host has not been decommissioned or re-provisioned.
If the unhealthy host has been decommissioned or re-provisioned <a href="https://docs.cfengine.com/docs/' . $cf_major_minor_version . '/reference-enterprise-api-ref-host.html#remove-host-from-the-hub">delete it</a>.'
];

$cfengineStoppedAtHosts = [
    'question' => 'CFEngine stopped at hosts',
    'response' => 'cf-serverd is required for report collection. Ensure that it is running on the affected host.'
];

$VMCloning = [
    'question' => 'Host cloned',
    'response' => 'When hosts are cloned with the intention of creating a new independent host the key pair used by cfengine to establish identity and trust should be re-generated.
To remediate establish a new host identity. First remove the host key pair by deleting the private and public key <pre>$(sys.workdir)/ppkeys/localhost.priv and $(sys.workdir)/ppkeys/localhost.pub (typically /var/cfengine/ppkeys/localhost.*)</pre>. Then generate a new key pair by running <b>cf-key</b>. In order to avoid reporting information for the previous identity <b>sys.statedir</b> should also be purged.
For best results perform a clean install of cfengine. For a clean install uninstall cfengine, remove sys.workdir (typically /var/cfengine), re-install cfengine, and bootstrap to the desired hub.'
];

$nonStandardInstallation = [
    'question' => 'Non-standard installation',
    'response' => 'When cfengine is deployed in a non-standard way the key pair used to establish identity and trust may have been included in the install.
To remediate establish a new host identity. First remove the host key pair by deleting the private and public key <pre>$(sys.workdir)/ppkeys/localhost.priv and $(sys.workdir)/ppkeys/localhost.pub (typically /var/cfengine/ppkeys/localhost. or C:\Program Files\Cfengine\ppkeys\localhost.)</pre>. Then generate a new key pair by running <b>cf-key</b>. In order to avoid reporting information for the previous identity <b>sys.statedir</b> should also be purged.
For best results use a clean install of cfengine from an official package. For a clean install uninstall cfengine, remove sys.workdir (typically /var/cfengine), re-install cfengine, and bootstrap to the desired hub.'
];

$hostDeployedFromTemplate = [
    'question' => 'Host deployed from template',
    'response' => 'In virtualized environments it is common for hosts to be deployed from a template where cfengine has been installed.
To remediate establish a new host identity first remove the host key pair by deleting the private and public key <pre>$(sys.workdir)/ppkeys/localhost.priv and $(sys.workdir)/ppkeys/localhost.pub (typically /var/cfengine/ppkeys/localhost.*)</pre>. Then generate a new key pair by running <b>cf-key</b>.
To avoid the condition be sure to remove the key pair used to establish identity and trust when creating/modifying templates. For best results use a clean install of cfengine. Consider using a first boot script to install cfengine the first time a host provisioned from a template boots.'
];

$cfExecdStopped = [
    'question' => 'cf-execd/cronjob stopped',
    'response' => '<p>Typically cf-agent is executed by cf-execd. If the process is not running, the agent will not be executed.</p>
<p>Check to see if the cf-execd process is running:</p>
systemd:
<pre>systemctl status cf-execd</pre>
sysvinit:
<pre>service cfengine3 status</pre>
Troubleshooting:
<pre>ps aux | grep [c]f-execd</pre>
<p>Start the service if it\'s not running.</p>
systemd:
<pre>systemctl start cf-execd</pre>
sysvinit:
<pre>service cfengine3 start</pre>
Troubleshooting:
<pre>/var/cfengine/bin/cf-execd -Fv</pre>'
];

$cfAgentCrashing = [
    'question' => 'The cf-agent binary is crashing, e.g. due to lmdb corruption',
    'response' => '<p>On rare occasion cf-agent crashes during the run. Crashes can be caused corrupt policy or embedded databases which may become corrupt in full disk conditions.</p>

<p>Errors that may indicate embedded database corruption include:</p>
<ul>
<li>mdb.c:5404: Assertion \'IS_LEAF(mp)\' failed in mdb_cursor_next()</li>
<li>Program received signal SIGBUS, Bus error.</li>
</ul>

<p>Backup the LMDB databases. Send the backup with any support requests you wish to submit.</p>

<pre>cf-check backup</pre>

<pre>
[root@hub ~]# cf-check backup
    info: No filenames specified, defaulting to .lmdb files in /var/cfengine/state/
    info: Backing up to \'/var/cfengine/backups/1561389044/\'
    info: Copying: \'/var/cfengine/state/nova_agent_execution.lmdb\' -> \'/var/cfengine/backups/1561389044/nova_agent_execution.lmdb\'
    info: Copying: \'/var/cfengine/state/cf_state.lmdb\' -> \'/var/cfengine/backups/1561389044/cf_state.lmdb\'
    info: Copying: \'/var/cfengine/state/packages_updates_yum.lmdb\' -> \'/var/cfengine/backups/1561389044/packages_updates_yum.lmdb\'
    info: Copying: \'/var/cfengine/state/history.lmdb\' -> \'/var/cfengine/backups/1561389044/history.lmdb\'
    info: Copying: \'/var/cfengine/state/nova_static.lmdb\' -> \'/var/cfengine/backups/1561389044/nova_static.lmdb\'
    info: Copying: \'/var/cfengine/state/cf_lock.lmdb\' -> \'/var/cfengine/backups/1561389044/cf_lock.lmdb\'
    info: Copying: \'/var/cfengine/state/performance.lmdb\' -> \'/var/cfengine/backups/1561389044/performance.lmdb\'
    info: Copying: \'/var/cfengine/state/packages_installed_yum.lmdb\' -> \'/var/cfengine/backups/1561389044/packages_installed_yum.lmdb\'
    info: Copying: \'/var/cfengine/state/cf_lastseen.lmdb\' -> \'/var/cfengine/backups/1561389044/cf_lastseen.lmdb\'
    info: Copying: \'/var/cfengine/state/nova_track.lmdb\' -> \'/var/cfengine/backups/1561389044/nova_track.lmdb\'
    info: Copying: \'/var/cfengine/state/cf_changes.lmdb\' -> \'/var/cfengine/backups/1561389044/cf_changes.lmdb\'
    info: Copying: \'/var/cfengine/state/cf_observations.lmdb\' -> \'/var/cfengine/backups/1561389044/cf_observations.lmdb\'
    info: Copying: \'/var/cfengine/state/nova_measures.lmdb\' -> \'/var/cfengine/backups/1561389044/nova_measures.lmdb\'
</pre>

<p>Delete the lmdb databases (they will be automatically re-generated). Note that this will clear all persistent classes and promise locks.</p>

<pre>rm /var/cfengine/state/*.lmdb*</pre>
 '
];

$hubClientTimeSkew = [
    'question' => 'Hub and Client time skew',
    'response' => '<p>If the hub and client system time are not in sync, particularly when the hub system time
is ahead of a client this can cause a perpetual health condition where reported agent executions appear to lag.</p>
<p>Check to see if hub and client system time are aligned.:</p>
<pre>LC_TIME="C.UTF-8" date</pre>
<p>Align the system times manually or consider configuring time synchronization.</p>'
];

$machineSuspended = [
    'question' => 'Machine was just rebooted or otherwise suspended',
    'response' => '<p>If you are running CFEngine on workstations / laptops or inside Virtual Machines (VMs) it could be that the host hasn\'t had time since it was brought back from sleep / suspension / reboot etc. </p>
<p>This could happen if you closed your laptop recently, making it go into sleep and suspending all running VMs, or if you just booted your computer.</p>
<p>In these cases the problem should resolve itself after some minutes, when the machines have been kept running and had time to perform its periodic tasks (enforcing the desired state in the policy set using the cf-agent binary) and report back on the results.</p>
<p>To speed up the process, you can click on the affected hosts and click the "Trigger agent run" action button (in the top right corner, with a play icon).</p>'
];

$policySyntaxError = [
    'question' => 'Policy syntax error',
    'response' => '<p>Syntax errors in policy can cause the agent to not complete its run.</p>
<p>Test your policy with cf-promises. For example cf-promises -cf ./update.cf; cf-promises -cf ./update.cf.</p>
<p><b>Note</b>: When using dynamic inputs cf-promises may not test all of your policy. Consider defining classes that load different parts of policy. For example: cf-promises --define extra_class -f ./update.cf; cf-promises --define extra_class -f ./promises.cf</p>'
];

$abortclasses = [
    'question' => 'Abortclasses',
    'response' => 'Agents defining abortclasses may abort before reporting enough information to be visible in Mission Portal.'
];

$sameName = [
    'question' => 'Multiple hosts report having same hostname.',
    'response' => ''
];


/**
 * Predefined list of host diagnostic reports
 */
$config['healthDiagnosticReports'] = [
    'notRecentlyCollected' => [
        'title'           => 'Unreachable hosts',
        'description'     => 'Reports from host has been collected in the past, but not recently (as defined by "Unreachable host threshold").',
        'recommendations' => [
            $machineSuspended,
            $tooFewLicense,
            $cfengineStoppedAtHosts,
            $hostsOffline,
            $hostsDecommissioned,
            $notAbleToCollect,
        ],
    ],
    'lastAgentRunUnsuccessful' => [
        'title'           => 'Policy errors',
        'description'     => 'Reports have recently been collected and cf-agent has completed a run with an error.',
        'recommendations' => [
            $policySyntaxError,
            $abortclasses
        ],
    ],
    'hostsUsingSameIdentity' => [
        'title'           => 'Duplicate IDs',
        'description'     => 'CFEngine hosts are identified by the CFEngine key they use. If two or more hosts use the same key the reports will be very unreliable. This is detected by exchanging randomized cookies(tokens) during report collections. If a client sends a mismatching cookie (compared to last collection), it indicates that multiple hosts are using the same ID.',
        'recommendations' => [
            $VMCloning,
            $nonStandardInstallation,
            $hostDeployedFromTemplate
        ],
    ],
    'hostsNeverCollected' => [
        'title'           => 'Missing reporting data',
        'description'     => 'Host has connected to hub (to get policy), but reports have never been collected from it.',
        'recommendations' => [
            $firewall,
            $tooFewLicense,
            $communityEdition,
            $accessPolicy,
            $notAbleToCollect
        ],
    ],
    'agentNotRunRecently' => [
        'title'           => 'Outdated reporting data',
        'description'     => 'There is no data to prove that your policy, describing your desired state, is being successfully enforced. The host is communicating correctly and sending its reports, but the data is outdated (there are no recent reports), indicating that there hasn\'t been any policy runs recently (no cf-agent binary runs within the last 10 minutes or 1.3 times the average agent run time if greater than 10 minutes).',
        'recommendations' => [
            $machineSuspended,
            $cfExecdStopped,
            $cfAgentCrashing,
            $hubClientTimeSkew
        ],
    ],
    'hostsUsingSameName' => [
        'title'           => 'Duplicate hostnames',
        'description'     => 'multiple host identities reporting the same host identifier (by default hostname derived from default:sys.fqhost variable but changeable in Settings -> Host identifier)',
        'recommendations' => [
            $sameName
        ],
    ],
    'deletedHostsReport' => [
        'title'           => 'Deleted hosts still reporting',
        'description'     => 'Deleting hosts should be done after each host has been completely decommissioned or CFEngine has been uninstalled on each host. When hosts which have previously been deleted are still reporting, this indicates a problem.',
        'recommendations' => [],
        'hideDefaultButtons' => true, // this report type cannot be exported as it uses custom API call to get report data, not default Query API
        'showAdditionalDeleteActions' => true 
    ],
];
