Extend NixOS: Difference between revisions

imported>Fadenb
No edit summary
imported>Fadenb
m Syntax highlighting
Line 16: Line 16:


The simplest way to implement this is to add a simple snippet of code to the <code>/etc/nixos/configuration.nix</code> file:
The simplest way to implement this is to add a simple snippet of code to the <code>/etc/nixos/configuration.nix</code> file:
 
<syntaxhighlight lang="nix">
  {pkgs, ...}:
  {pkgs, ...}:
   
   
Line 25: Line 25:
     description = "Start the irc client of username.";
     description = "Start the irc client of username.";
     startOn = "started network-interfaces";
     startOn = "started network-interfaces";
     exec = <nowiki>''/var/setuid-wrappers/sudo -u username -- ${pkgs.screen}/bin/screen -m -d -S irc ${pkgs.irssi}/bin/irssi'';</nowiki>
     exec = ''/var/setuid-wrappers/sudo -u username -- ${pkgs.screen}/bin/screen -m -d -S irc ${pkgs.irssi}/bin/irssi'';
   };
   };
   
   
Line 33: Line 33:
   # ... usual configuration ...
   # ... usual configuration ...
  }
  }
 
</syntaxhighlight>
What does this do? The <code>jobs.ircSession</code> bit is an option which adds a new system service. This option is defined elsewhere in the NixOS configuration files. This is one of many options; you can see a list of all NixOS configuration options in the [https://nixos.org/nixos/manual/options.html NixOS Manual: List of Options] (or use https://nixos.org/nixos/options.html to search for options). We add attributes to this option to configure our new service. As you can see, we configure it to start when the network connects, and to execute a shell command.
What does this do? The <code>jobs.ircSession</code> bit is an option which adds a new system service. This option is defined elsewhere in the NixOS configuration files. This is one of many options; you can see a list of all NixOS configuration options in the [https://nixos.org/nixos/manual/options.html NixOS Manual: List of Options] (or use https://nixos.org/nixos/options.html to search for options). We add attributes to this option to configure our new service. As you can see, we configure it to start when the network connects, and to execute a shell command.


Line 43: Line 43:


NixOS is now using systemd by default, and thus the way to define nix modules has changed.  Here's the commented equivalent of the snippet above:
NixOS is now using systemd by default, and thus the way to define nix modules has changed.  Here's the commented equivalent of the snippet above:
 
<syntaxhighlight lang="nix">
   {
   {
     systemd.services.ircSession = {
     systemd.services.ircSession = {
Line 51: Line 51:
         Type = "forking";
         Type = "forking";
         User = "username";
         User = "username";
         ExecStart = <nowiki>''${pkgs.screen}/bin/screen -dmS irc ${pkgs.irssi}/bin/irssi''</nowiki>;         
         ExecStart = ''${pkgs.screen}/bin/screen -dmS irc ${pkgs.irssi}/bin/irssi'';         
         ExecStop = <nowiki>''${pkgs.screen}/bin/screen -S irc -X quit''</nowiki>;
         ExecStop = ''${pkgs.screen}/bin/screen -S irc -X quit'';
       };
       };
     };
     };
   }
   }
 
</syntaxhighlight>
== Conditional Implementation ==
== Conditional Implementation ==


Line 62: Line 62:


We can use the <code>mkIf</code> function in the <code>configuration.nix</code> file to add conditional behavior. Here's the new implementation:
We can use the <code>mkIf</code> function in the <code>configuration.nix</code> file to add conditional behavior. Here's the new implementation:
 
<syntaxhighlight lang="nix">
  {config, pkgs, ...}:
  {config, pkgs, ...}:
   
   
Line 70: Line 70:
       description = "Start the irc client of username.";
       description = "Start the irc client of username.";
       startOn = "started network-interfaces";
       startOn = "started network-interfaces";
       exec = <nowiki>''/var/setuid-wrappers/sudo -u username -- ${pkgs.screen}/bin/screen -m -d -S irc ${pkgs.irssi}/bin/irssi'';</nowiki>
       exec = ''/var/setuid-wrappers/sudo -u username -- ${pkgs.screen}/bin/screen -m -d -S irc ${pkgs.irssi}/bin/irssi'';
     };
     };
   };
   };
Line 79: Line 79:
   # ... usual configuration ...
   # ... usual configuration ...
  }
  }
 
</syntaxhighlight>
This works, but if we use too many conditionals, our code will become difficult to read and modify. For example, what do we do when we want to change the hostname?
This works, but if we use too many conditionals, our code will become difficult to read and modify. For example, what do we do when we want to change the hostname?


Line 87: Line 87:


If we move the IRC stuff into the <code>irc-client.nix</code> file, we change the <code>configuration.nix</code> file like this:
If we move the IRC stuff into the <code>irc-client.nix</code> file, we change the <code>configuration.nix</code> file like this:
 
<syntaxhighlight lang="nix">
  {
  {
   imports = [
   imports = [
Line 95: Line 95:
   # ... usual configuration ...
   # ... usual configuration ...
  }
  }
 
</syntaxhighlight>
The <code>irc-client.nix</code> file will, of course, look like this:
The <code>irc-client.nix</code> file will, of course, look like this:
 
<syntaxhighlight lang="nix">
  {config, pkgs, ...}:
  {config, pkgs, ...}:
   
   
Line 104: Line 104:
     description = "Start the irc client of username.";
     description = "Start the irc client of username.";
     startOn = "started network-interfaces";
     startOn = "started network-interfaces";
     exec = <nowiki>''/var/setuid-wrappers/sudo -u username -- ${pkgs.screen}/bin/screen -m -d -S irc ${pkgs.irssi}/bin/irssi'';</nowiki>
     exec = ''/var/setuid-wrappers/sudo -u username -- ${pkgs.screen}/bin/screen -m -d -S irc ${pkgs.irssi}/bin/irssi'';
   };
   };
   
   
Line 110: Line 110:
   security.sudo.enable = true;
   security.sudo.enable = true;
  }
  }
 
</syntaxhighlight>
If we organize our configuration like this, sharing it across machines is easier. In addition, our IRC client can be consistent across machines that choose to use it.
If we organize our configuration like this, sharing it across machines is easier. In addition, our IRC client can be consistent across machines that choose to use it.


Line 119: Line 119:
NixOS supports this idea, but it is called "options". We can add options to our module for both the condition and the username. Here is what a <code>irc-client.nix</code> module with parameters/options looks like:
NixOS supports this idea, but it is called "options". We can add options to our module for both the condition and the username. Here is what a <code>irc-client.nix</code> module with parameters/options looks like:


<pre>
<syntaxhighlight lang="nix">
  {config, pkgs, ...}:
  {config, pkgs, ...}:
   
   
Line 160: Line 160:
   };
   };
  }
  }
</pre>
</syntaxhighlight>


This module is now independent of the system. Now, we must update our <code>configuration.nix</code> file to pass our condition and hostname into our new module.
This module is now independent of the system. Now, we must update our <code>configuration.nix</code> file to pass our condition and hostname into our new module.


<pre>
<syntaxhighlight lang="nix">
{config, ...}:
{config, ...}:


Line 177: Line 177:
   # ... usual configuration ...
   # ... usual configuration ...
  }
  }
</pre>
</syntaxhighlight>


== Multiple Daemons ==
== Multiple Daemons ==


Now, suppose your server has multiple people as users, and each wants the same IRC client running in background. One possibility is to replace the user name with a list of user names.  A better solution, for this tutorial, is to '''extend''' the <code>jobs</code> option. This will allow us to add "IRC jobs", each of which is for a specific user. This should create configuration options like this:
Now, suppose your server has multiple people as users, and each wants the same IRC client running in background. One possibility is to replace the user name with a list of user names.  A better solution, for this tutorial, is to '''extend''' the <code>jobs</code> option. This will allow us to add "IRC jobs", each of which is for a specific user. This should create configuration options like this:
 
<syntaxhighlight lang="nix">
jobs.ircClient.user  = "User1";
jobs.ircClient.user  = "User1";
jobs.ircClient.enable = true;
jobs.ircClient.enable = true;
</syntaxhighlight>


The following code will add more options inside the <code>jobs.<name></code> option. This code is quite advanced, using many concepts from functional language paradigm.
The following code will add more options inside the <code>jobs.<name></code> option. This code is quite advanced, using many concepts from functional language paradigm.


<pre>
<syntaxhighlight lang="nix">
  {config, pkgs, ...}:
  {config, pkgs, ...}:
   
   
Line 241: Line 242:
   };
   };
  }
  }
</pre>
</syntaxhighlight>


= Testing Configuration Changes in a VM =
= Testing Configuration Changes in a VM =
Line 249: Line 250:
To see how this works, create a file like this:
To see how this works, create a file like this:


<pre>
<syntaxhighlight lang="nix">
  {config, pkgs, ...}:
  {config, pkgs, ...}:
  {
  {
Line 276: Line 277:
   };
   };
  }
  }
</pre>
</syntaxhighlight>


Then, we build the new configuration inside a VM. If we named the above file <code>my-new-service.nix</code>, we can use these commands:
Then, we build the new configuration inside a VM. If we named the above file <code>my-new-service.nix</code>, we can use these commands:
 
<syntaxhighlight lang="console">
  ## Create a VM from the new configuration.
  # Create a VM from the new configuration.
  $ NIXOS_CONFIG=`pwd`/vmtest.nix nixos-rebuild  -I nixos=/path/to/nixos/ build-vm
  $ NIXOS_CONFIG=`pwd`/vmtest.nix nixos-rebuild  -I nixos=/path/to/nixos/ build-vm
  ## Then start it.
  # Then start it.
  $ ./result/bin/run-vmhost-vm
  $ ./result/bin/run-vmhost-vm
</syntaxhighlight>


= What Next? =
= What Next? =