[Nix-dev] NixOS: Introduce sub-configurations

Nicolas Pierron nicolas.b.pierron at gmail.com
Sun May 3 23:30:01 CEST 2009


Hi Nixers,

This mail presents a way to improve documentation as well as the
modularity in "instances".  Section 1 clarifies what I call an
"instance".  Section 2 highlights issues related to instances.
Section 3 introduces sub-configurations to tackle modularity and
documentation issues.


1/ Instances


In this mail, an instance correspond to a part of a configuration
which can be registered from any places.  This naming implies that the
configuration which aggregate all definitions (instances) will use
them as a job where each instance has its "own life".  File systems,
Apache virtual hosts and upstart jobs configurations are instances.
Usually, they are sets of options.

fileSystems = [
  { device = "/dev/hda1"; mountPoint = "/"; }
  { device = "/dev/hda2"; fsType = "ext3"; mountPoint = "/data";
options = "data=journal"; }
  { label = "bigdisk"; mountPoint = "/bigdisk"; }
];

extraJobs = [
  { name = "test1"; job = ".." "; }
  { name = "test2"; job = ".." "; }
];

In each case, one option is used to aggregate every instances into a
list.  The list is processed by the main configuration file which own
the option.


2/ Issues


Two issues are related to instances:

- Documentation:

Instances are sets composed of multiple attributes.  The attributes
are documented in the option containing the list of sets.  The
description attribute is usually getting bigger and bigger.  Apache
virtual hosts have their own file of options with their own
descriptions (cf upstart-jobs/apache-httpd/per-server-options.nix).
Unfortunately, this options does not show-up directly under the
virtualHosts option which is not good as you may have to look at the
sources to know what option you can set.  At the same time, the link
between the instances and the options is made by the implementation
which means that you have to investigate in the implementation to
understand this.  Hiding this relation is a bad thing because when we
will have a GUI, you will have to rely on the documentation to add a
new instance.

- Modularity:

The modification implies by the previous issue highlight that we might
want to add mkOption inside the instances.  mkOption are associated to
the modularity shown in NixOS and we might expect to handle extensions
of the instances.  The hypothetical example below highlights that we
might want to add complex file system mount-procedure and that we
might implements current option based on lower level options.

fileSystems = [
  { fsType = "vfat"; device = "/dev/sda"; mountPoint = "/mnt/usb"; }
  { mountCommand = "mount -t vfat /dev/sda /mnt/usb"; }
];

mountCommad = mkOption {
  default = "${mount} -t ${cfg.fsType} ${cfg.device} ${cfg.mountPoint}";
  description = "Command used to mount the file system."
};

The file system example is a simple case but this could be
extrapolated to XServer devices as well as Apache virtual hosts in
order to factor common parameters or usual configuration (subversion
server ?)

The modularity issue is controversial because this can be handled by
adding an extra list of instances which is translate into instances of
the previous list.


3/ sub-configurations


Sub-configurations are special options which have the ability to
contains extra option declarations.  Two options are defined on
sub-configuration, which target the first declaration and extensions.

fileSystems = mkSubConfigs {
  default = null;
  example = [ { device = "/dev/hda1"; mountPoint = "/"; } ];
  description = "List of mounted file systems";
} {
  devices = mkOption { .. };
  mountPoint = mkOption { .. };
};

The input of the fileSystems attribute is left as it is and the
options are documented inside the manual ( cf
http://www.nbp.name/nixos/manual.html ).  Sub-configuration options
are displayed as " fileSystems.*.devices " with the corresponding
default values and examples in addition to the documentation of the "
fileSystems " option.

An overkill extension could be made for fileSystems to add a nice
support to nfs servers:

let
  fileSystemsOption = {
    nfsServerName = mkOption { .. };
  }
in

fileSystems = xtSubConfigs (

  {config, ...}: mkIf (config.nfsServerName != null) {
    require = fileSystemsOption;

    device = config.nfsServerName + ":/share"
    mountPoint = "/mnt/" + config.nfsServerName;
    fsType = "nfs";
    options = "...";
  }

);

Even if this example is pointless because it would be easier to write
a small function to do it instead, you have to keep in mind that this
option will be documented and visible inside a GUI at the opposite of
a function.  In the same way, extensions of Apache virtual hosts could
be made to abstract over the low-level options of Apache.

-- 
Nicolas Pierron
http://www.linkedin.com/in/nicolasbpierron
- If you are doing something twice then you should try to do it once.



More information about the nix-dev mailing list