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
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
'';
@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)
@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