bundle agent env_classification
# @brief Classify environment
{
  vars:
      # We use presence of key files to know the hosts environment
      "environment_semaphores" slist => { "/etc/prod", "/etc/staging" };
      "environment"
        string => ifelse( filesexist( @(environment_semaphores) ), "incoherent",
                          fileexists("/etc/prod"), "production",
                          fileexists("/etc/staging"), "staging",
                          "unknown" );
      "env_issue_msg"
        string => ifelse( strcmp( "incoherent", $(environment) ),
                                  "WARNING: Environment incoherent (multiple environment semaphores)",
                          strcmp( "unknown", $(environment) ),
                                  "WARNING: Environment unknown (missing environment semaphores)",
                          "Host environment classified as $(environment)");

      # This is to extract the cfengine role ( hub or client )
      "cf_role"
        string => ifelse( "policy_server", "Policy Server", "Policy Client");

  classes:

      # We define a class for the selected environment. It's useful for making
      # decisions in other policies

      "env_$(environment)"
        expression => "any",
        scope => "namespace";

}
bundle agent env_info
# @brief Relevant environment information
{
  vars:
      ## Based on the environment we define different contacts.
      "admin_contact"
        slist => { "admin@acme.com", "oncall@acme.com" },
        if => strcmp( $(env_classification.environment), "production" );

      "admin_contact"
        slist => { "dev@acme.com" },
        if => strcmp( $(env_classification.environment), "staging" );

      "admin_contact"
        slist => { "root@localhost" },
        if => strcmp( $(env_classification.environment), "unknown" );

      ## This is to extract the available package updates status
      "updates_available"
        data => packageupdatesmatching(".*", ".*", ".*", ".*");
      "count_updates" int => length("updates_available");

  classes:

      # We define a class indicating there are updates available, it might be
      # useful for various different policies.

      "have_updates_available"
        expression => isgreaterthan( $(count_updates), 0),
        scope => "namespace";

}
bundle agent motd {

  vars:
      "motd_path" string => "/etc/motd";

      # It's considered best practice to prepare a data container holding the
      # information you need to render the template instead of relying on
      # current datastate()

      # First we extract currently defined classes from datastate(), then we
      # construct the template data.

      "_state" data => datastate(),
        if => not( isvariable ( $(this.promiser) ) ); # Limit recursive growth
                                                      # and multiple calls to
                                                      # datastate() over
                                                      # multiple passes.

      "template_data"
        data => mergedata('{ "fqhost": "$(sys.fqhost)",
                   "primary_ip": "$(sys.ipv4)",
                   "cf_version": "$(sys.cf_version)",
                   "issue_msg": "$(env_classification.env_issue_msg)",
                   "cf_role":  "$(env_classification.cf_role)",
                   "count_updates": "$(env_info.count_updates)",
                   "contacts": env_info.admin_contact,
                   "classes": _state[classes]
        }');

  files:
      "$(motd_path)"
        create => "true",
        template_method => "inline_mustache",
        template_data => @(template_data),
        edit_template_string => '# Managed by CFEngine
{{{issue_msg}}}
  ***
  *** 	 Welcome to {{{fqhost}}}
  ***

* *** *	     CFEngine Role: {{{cf_role}}}
* *** *      CFEngine Version:{{{cf_version}}}
* *** *
*     *      Host IP: {{{primary_ip}}}
  ***        {{#classes.have_updates_available}}{{{count_updates}}} package updates available.{{/classes.have_updates_available}}{{^classes.have_updates_available}}No package updates available or status unknown.{{/classes.have_updates_available}}
  * *
  * *
  * *
             For support contact:{{#contacts}}
               - {{{.}}}{{/contacts}}$(const.n)';

}
bundle agent __main__
{
  methods:
      "env_classification";
      "env_info";
      "motd";
}
