[Nix-dev] [disnix] per-host configuration file generation

Sander van der Burg - EWI S.vanderBurg at tudelft.nl
Thu Mar 31 13:29:20 CEST 2011


Hi Kamil,

Good to hear that you have discovered our tooling :)

If I understand everything correctly, you want to "tune" services to have host specific settings, right?

In most examples I have used for Disnix, services are relocatable and are built/configured only using properties of their intra-dependencies and inter-dependencies. If a service needs machine specific settings (e.g. a port number), you basically have to create a tuned variant, configured for that particular machine. I have encountered a similar issue in the Disnix TCP proxy example. To tune services for a particular host, you can write a Disnix expression like this:

{stdenv}:
{port}:
{hello_world_server}:

let 
  makeFlags = "PREFIX=$out srcPort=${toString port} destHostname=${hello_world_server.target.hostname} destPort=${toString (hello_world_server.port)}";
in
stdenv.mkDerivation {
  name = "disnix-tcp-proxy";
  src = ../../../services/disnix-tcp-proxy;
  buildPhase = "make ${makeFlags}";
  installPhase = "make ${makeFlags} install";
}

Basically, this expression takes 3 arguments. The first argument are its intra-dependencies (similar to ordinary Disnix expressions, the second argument is a port-number (which is configured in the services model), the third argument are the inter-dependencies. As you can see, the value of the port number is configurable, and in the stdenv.mkDerivation function (which builds the service) the makeFlags argument is used to pass the port value to make.

In the services.nix model, the port number is provided and configured:

{system, distribution, pkgs}:

let customPkgs = import ../top-level/all-packages.nix { inherit system pkgs; };
in
rec {
  hello_world_server = rec {
    name = "hello_world_server";
    pkg = customPkgs.hello_world_server { inherit port; }; # calling the previous expression with desired 'port' argument
    port = 5000; # This is the TCP port where we want to run the service on
    type = "wrapper";
  };
  
  ...
}

You may wonder why we put this 'port' attribute in the services model? This makes it possible to retrieve those values through inter-dependency arguments. So for instance, if you have a service which has an inter-dependency on the hello_world_server and you want to know the port number on which it is running you can fetch this property directly through inter-dependency arguments:

{stdenv, inetutils}:                                                                                                                                                                                               
{hello_world_server}: # Refers to the hello_world_service defined in services.nix                                                                                                                                                                                           
                                                                                                                                                                                                                   
let makeFlags = "PREFIX=$out helloWorldHostname=${hello_world_server.target.hostname} helloWorldPort=${toString (hello_world_server.port)} inetutils=${inetutils}"; # Configured the client to use the port number of the server.
                                              
in                                                                                                                                                                                                                 
stdenv.mkDerivation {                                                                                                                                                                                              
  name = "hello-world-client";                                                                                                                                                                                     
  src = ../../../services/hello-world-client;                                                                                                                                                                      
  buildPhase = "make ${makeFlags}";
  installPhase = "make ${makeFlags} install";
}

The expression above shows the Disnix expression of the hello world client. This expression fetches the 'port' attribute from the hello_world_server inter-dependency argument. In the body the client is configured to use to port value of the server.

I hope this explanation clarifies some things a bit. You can obtain the source code and Nix expressions from the example I have given from Disnix download page, or through Subversion: https://svn.nixos.org/repos/nix/disnix/examples/disnix-proxy-example/trunk

-----Original Message-----
From: nix-dev-bounces at cs.uu.nl on behalf of Kamil Klimkiewicz
Sent: Thu 3/31/2011 12:25 AM
To: nix-dev at cs.uu.nl
Subject: [Nix-dev] [disnix] per-host configuration file generation
 
Hi guys,

I found out about Nix/NixOS/Disnix a couple of days ago, by accident. I
have to say it's a great piece of software. It was a little tricky to
grasp the whole expression language (especially given I last used any
functional language 5+ years ago) at first, but now I think I'm slowly
getting used to it.

Anyway, I have one question about disnix. I'm trying to use it for
deployment of Django application (together with all dependent services -
PostgreSQL, pgpool, nginx, gunicorn WSGI server, etc.). The whole thing
will sit on Ubuntu server(s) - for various reasons. Everything looks
great so far.

But I got into a little problem. Let's say I have a nginx service that
sits on single machine and django/gunicorn/pgpool service that sits on a
couple of machines. How would you go about providing configuration file
for pgpool service that depends on the machine this service is running
on? Let's say I want the pgpool service to use different ports on
particular servers. My current ideas are:
- Generate configuration files for each machine in advance using pgpool
  service Nix expression - I simply store files named
  pgpool-machine1.conf, pgpool-machine2.conf, etc. in the pgpool's nix
  store. This has one major drawback - whenever I change configuration
  for single machine I have to distribute the service to all pgpool
  machines and possibly it will restart pgpool services on all machines.
- Generate configuration files in service activation script - this
  doesn't look too nix-y in my opinion.
- Create separate "subservice" for each machine.

How would you resolve this issue? What I have in mind is some kind of
map that takes a service generator function and a list of machines, but
I don't see a way to make it work. Any ideas?

-- 
Best regards,
Kamil Klimkiewicz
_______________________________________________
nix-dev mailing list
nix-dev at cs.uu.nl
https://mail.cs.uu.nl/mailman/listinfo/nix-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.science.uu.nl/pipermail/nix-dev/attachments/20110331/45345e2d/attachment.html 


More information about the nix-dev mailing list