Alternative to Salt grains or Puppet facts?

Hi,

Is there an alternative for such a system at NixOS?
I would like to create a dynamic /etc/motd.

As an example:

Welcome to  {{ grains['fqdn'] }}

  - THIS SERVER IS MANAGED BY SALTSTACK!
  - DO NOT CHANGE ANYTHING LOCALLY!

IP:               {% for ip in grains['ipv4'] %}{% if ip != '127.0.0.1' %}{{ ip }} {% endif %}{% endfor %}
CPU:              {{ grains['num_cpus'] }} x {{ grains['cpu_model'] }}
MEM:              {{ grains['mem_total'] }} MB

OS:               {{ grains['lsb_distrib_description'] }}
Kernel:           {{ grains['kernelversion'] }}

Virtual:          {{ grains['virtual'] }}
Salt:             {{ grains['saltversion'] }}
Master:           {{ grains['master'] }}

You won’t get all information from the nixos configuration you use in your motd is using runtime values.
However you can explore some information using nix repl:

$ nix repl '<nixpkgs/nixos>'
Welcome to Nix version 2.2.2. Type :? for help.

Loading '<nixpkgs/nixos>'...
Added 6 variables.
nix-repl> config.networking.hostName
"turingmachine"

For the remaining information you could also use an executable motd (I think there was a way to have a script instead of a static text file).

The MOTD has to be a static text file, so you can’t just put a script in there. There’s also no place in the NixOS configuration to put the CPU/Memory (unless you count nix.maxJobs, which doesn’t neccesarily reflect your number of cores and certainly doesn’t tell you the speed).

The usual approach is to generate the file regularly with a cronjob or systemd timer. The benefit of a timer is that you could potentially trigger it when your network changes or you switch to a new configuration.

The other option is to basically output it programs.bash.loginShellInit, but of course that won’t work exactly the same for other shells.

For the static version you could use this:

  users.motd = with config; ''
    Welcome to ${networking.hostName}

    - This server is managed by NixOS
    - All changes are futile

    OS:      NixOS ${system.nixos.release} (${system.nixos.codeName})
    Version: ${system.nixos.version}
    Kernel:  ${boot.kernelPackages.kernel.version}
  '';

The output looks like this:

Welcome to kappa

- This server is managed by NixOS
- All changes are futile

OS:      NixOS 19.03 (Koi)
Version: 19.03.172921.d77e3bd6613
Kernel:  4.19.52
2 Likes

I use custom banner scripts to display dynamic data on SSH login. The script is then included in loginShellInit (as already indicated by manveru). The caveat here is to make sure that the banner is only shown for interactive user logins or otherwise it would break tools like nixops, scp, etc.

environment.loginShellInit = ''                                                                                                    
   # disable for user root and non-interactive tools                                                                                
   if [ `id -u` != 0 ]; then                                                                                                        
     if [ "x''${SSH_TTY}" != "x" ]; then                                                                                            
       ${banner}/bin/banner                                                                                                         
     fi                                                                                                                             
   fi                                                                                                                               
 '';
2 Likes

Many thanks for all inputs.

@manveru
This looks very good for me but I get the following error when I start nixos-rebuild dry-run:

building the system configuration...
error: undefined variable 'nixos' at /etc/nixos/modules/defaults/users.nix:35:22
(use '--show-trace' to show detailed location information)

I’ve only been using NixOS for a day :slight_smile:

Sorry, somehow my clipboard contents were switched, I updated the post with the working version.

1 Like

@markuskowa
This is probably an easier solution to avoid producing output that programs cannot deal with. It checks if stdout (file descriptor 1) is a terminal. If a program explicitely requests a terminal, then it should be able to deal with output intended for humans.

if [ ! -t 1 ]; then
${banner}/bin/banner
fi

This is the result:

$ ssh freya test -t 1 && echo terminal

$ ssh freya
[root@freya:~]# test -t 1 && echo terminal
terminal
1 Like

@tokudan Thanks! I didn’t know it can be made that simple.

@manveru
Thanks!

@all
Is it possible to display the status of a systemd unit?