Customize Message of the Day

Table of Contents

The Message of the Day is displayed when you log in or connect to a server. It typically shows information about the operating system, license information, last login, etc.

It is often useful to customize the Message of the Day to inform your users about some specifics of the system they are connecting to. In this example we render a /etc/motd using a mustache template and add useful information as:

  • The role of the server ( staging / production )
  • The hostname of the server
  • The CFEngine version we are running on the host
  • The CFEngine role of the server ( client / hub )
  • The administrative contacts details conditionally to the environment
  • The primary Ipv4 IP address
  • The number of packages updates available for this host

The bundle is defined like this:

body file control {
  # To make this policy "standalone" we load parts of the standard library that
  # we use
  inputs => { "$(sys.libdir)/files.cf", "$(sys.libdir)/packages.cf" };
}

bundle agent motd {

  vars:
    "motd_path" string => "/etc/motd";
    "template_path" string => "$(this.promise_filename).mustache";

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

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

    ## This is to define a production / stage example role for the server
    "environment_list" slist => { "/etc/prod", "/etc/staging" };
    "environment"
      string => ifelse( filesexist( @(environment_list) ), "unknown",
                        fileexists("/etc/prod"), "production",
                        fileexists("/etc/staging"), "staging",
                        "unknown" );

    ## Based on the environment we define different contatcs.
    "admin_contact"
      slist => { "admin@acme.com", "oncall@acme.com" },
      if => strcmp( $(environment), "production" );

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

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

  ## We define a class to conditionally render the role status in the final
  ## motd.
  classes:
    "env_$(environment)" expression => "any";

  ## In order to get package inventory, we need to have a legacy package
  ## promise.
  packages:
    "vim" -> { "https://dev.cfengine.com/issues/7864" }
      package_policy => "add";

  ## Here is where we render the mustache template
  files:
    "$(motd_path)"
      create => "true",
      perms => mog( 444, "root", "root"),
      template_method => "mustache",
      edit_template => "$(template_path)";

  ## These are good to understand what is going on.
  reports:
    DEBUG|DEBUG_motd::
      "DEBUG $(this.bundle): $(sys.cf_version) is the detected version";
      "DEBUG $(this.bundle): $(sys.fqhost) is the detected hostname";
      "DEBUG $(this.bundle): $(sys.ipv4) is the ipv4 address for $(sys.fqhost)";
      "DEBUG $(this.bundle): $(motd.cf_role) is the detected role";
      "DEBUG $(this.bundle): $(amount_updates) packages can be updated";
      "DEBUG $(this.bundle): This host is managed by $(admin_contact)";
}

This policy can be found in /var/cfengine/share/doc/examples/mustache_template_motd.cf and downloaded directly from github.

Here is the mustache:

{{#classes.env_unknown}} WARNING Environment Unknown{{/classes.env_unknown}}
      ¤¤¤
      ¤¤¤
      ¤¤¤     Welcome into {{{vars.sys.fqhost}}}

    ¤ ¤¤¤ ¤      This system is controlled by
    ¤ ¤¤¤ ¤      CFEngine {{{vars.sys.cf_version}}}
    ¤ ¤¤¤ ¤     And is a {{{vars.motd.cf_role}}}
    ¤     ¤
      ¤¤¤
      ¤ ¤  
      ¤ ¤  Host IP {{{vars.sys.ipv4}}}
      ¤ ¤  {{{vars.motd.amount_updates}}} package updates available.
                 {{#vars.motd.admin_contact}}Support Contact:
                   - {{{.}}}
{{/vars.motd.admin_contact}}

This policy can be found in /var/cfengine/share/doc/examples/mustache_template_motd.cf.mustache and downloaded directly from github.

Example run:

root@debian8:~/core/examples# cf-agent --no-lock --bundlesequence motd --define DEBUG_motd --file ./mustache_template_motd.cf
    info: Using command line specified bundlesequence
R: 3.7.2 is the detected version
R: debian8 is the detected hostname
R: 10.100.251.53 is the ipv4 address for debian8
R: Policy Client is the detected role for debian8
R: 20 packages can be updated
R: This host is managed by root@localhost
root@debian8:~/core/examples# cat /etc/motd
 WARNING Environment Unknown
      ¤¤¤
      ¤¤¤
      ¤¤¤     Welcome into debian8

    ¤ ¤¤¤ ¤      This system is controlled by
    ¤ ¤¤¤ ¤      CFEngine 3.8.0
    ¤ ¤¤¤ ¤     And is a Policy Client
    ¤     ¤
      ¤¤¤
      ¤ ¤ 
      ¤ ¤  Host IP 10.100.251.53
      ¤ ¤  20 package updates available.
                 Support Contact:
                   - root@localhost