├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README.md ├── bootstrap ├── configure.ac ├── doc ├── Makefile.am └── manual │ ├── Makefile.am │ ├── background.xml │ ├── index.xml │ ├── installation.xml │ ├── introduction.xml │ ├── style.css │ └── usage.xml ├── maintenance ├── Makefile.am └── man2docbook.bash ├── nix ├── Makefile.am ├── disnix-infrastructure-module.nix ├── generate-distributed-derivation.nix ├── generate-infrastructure.nix.in ├── generate-manifest.nix ├── generate-tests.nix.in ├── generate-testscript.nix ├── infrastructure.nix.in ├── instantiate.nix ├── lib.nix ├── manifest.nix └── testing.nix.in ├── release.nix ├── scripts ├── Makefile.am ├── checks ├── disnix-backdoor-client.in ├── disnix-nixops-client.in ├── disnixos-capture-manifest.in ├── disnixos-clean-snapshots.in ├── disnixos-collect-garbage.in ├── disnixos-convert-manifest.in ├── disnixos-convert.in ├── disnixos-delegate.in ├── disnixos-delete-network-state.in ├── disnixos-deploy-network.in ├── disnixos-env.in ├── disnixos-geninfra.in ├── disnixos-gentests.in ├── disnixos-instantiate.in ├── disnixos-manifest.in ├── disnixos-query.in ├── disnixos-reconstruct.in ├── disnixos-restore-network.in ├── disnixos-snapshot-network.in └── disnixos-vm-env.in ├── tests ├── deployment-infra-with-data.nix ├── deployment-infra.nix ├── deployment-nixops.nix ├── deployment-services-with-data.nix ├── deployment-services.nix ├── distbuild-infra.nix ├── distbuild-services.nix ├── generate-logical-config.nix ├── generate-logical-network.nix ├── generate-physical-config.nix ├── generate-physical-network-for-nixops.nix ├── generate-physical-network.nix ├── machine-with-nixops.nix ├── machine.nix ├── manifest │ ├── distribution-server.nix │ ├── distribution.nix │ ├── pkgs │ │ ├── default.nix │ │ ├── testService1.nix │ │ ├── testService2.nix │ │ └── testService3.nix │ ├── services.nix │ └── target-pkgs.nix ├── nixops-client.nix ├── snapshots.nix └── snapshots │ ├── distribution-reverse.nix │ ├── distribution-simple.nix │ ├── infrastructure.nix │ ├── services-state.nix │ └── wrapper.nix └── version /AUTHORS: -------------------------------------------------------------------------------- 1 | Sander van der Burg 2 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svanderburg/disnixos/b40646106d140eb2edab2d4662e68394d6fee7b0/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = scripts nix doc maintenance 2 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Version 0.9 2 | =========== 3 | - By default, disnix-nixops-client will work in single-user mode. The DISNIX_REMOTE_CLIENT environment variable can be set to disnix-client to enable multi-user mode. 4 | 5 | - The test infrastructure now also simulates a Disnix profile symlink for more accurate results 6 | 7 | - The test infrastructure now uses the Python implementation of NixOS' test driver 8 | 9 | - Introduced the --extra-params option to propagate additional parameters to the input models 10 | 11 | - disnixos-env also accepts the --undeploy paramater to completely undeploy an entire system 12 | 13 | Version 0.8 14 | =========== 15 | - disnixos-manifest generates deployment models for infrastructure deployment 16 | 17 | - disnixos-manifest, disnixos-instantiate, disnixos-delegate, disnixos-env, disnixos-vm-env can also work with packages models 18 | 19 | - New tools: disnixos-convert-manifest, disnixos-convert 20 | 21 | Version 0.7 22 | =========== 23 | - Add --shell support to the NixOps client 24 | 25 | - Added testsuite for the disnix-nixops-client tool 26 | 27 | Version 0.6 28 | =========== 29 | - Added disnixos-delegate, disnixos-capture-manifest, disnixos-reconstruct 30 | 31 | Version 0.5 32 | =========== 33 | - Compatibility fixes with current versions of Disnix and NixOps 34 | 35 | Version 0.4 36 | =========== 37 | - Add disnixos-snapshot-network and disnixos-restore-network to capture and restore state of entire NixOS configurations 38 | 39 | - Modify infrastructure to work with Disnix' new container formalism 40 | 41 | Version 0.3 42 | =========== 43 | - The distributed derivation and manifest generator now pass the XML input as files to support bigger ones (Nix 1.9 or newer required) 44 | 45 | - Implement snapshot and restore operations 46 | 47 | - Fix disnixos-manifest to correctly generate manifests that work with NixOps 48 | 49 | Version 0.2 50 | =========== 51 | - Machines in the network model can refer to each other through the 'node' parameter 52 | 53 | - Multiple network models are also supported, allowing someone to capture concerns separately 54 | 55 | - Added some more infrastructure level equivalents of certain core Disnix utilities: 56 | disnixos-{manifest,instantiate,collect-garbage,query} 57 | 58 | - NixOps can be used for infrastructure deployment instead of the core Disnix toolset 59 | 60 | - Various bug fixes 61 | 62 | - Implemented a test suite for the most common use cases 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DisnixOS 2 | ======== 3 | DisnixOS is a distributed infrastructure deployment extension for Disnix. 4 | Disnix's responsibility is to deploy distributable components (i.e. services) 5 | into a network of machines. However, the underlying system configurations of 6 | these machines (the infrastructure) also need to be deployed and upgraded. 7 | 8 | DisnixOS provides complementary infrastructure deployment using [NixOS](http://nixos.org/nixos), 9 | a Linux distribution that allows entire system configurations to be deployed with 10 | the Nix package manager from a single declarative specification. 11 | 12 | Optionally, it can use [NixOps](http://github.com/nixos/nixops), a NixOS-based 13 | cloud deployment tool to perform infrastructure deployment. NixOps supports 14 | automatic instantiation and provision of VM instances. 15 | 16 | Prerequisites 17 | ============= 18 | In order to build Disnix from source code, the following packages are required: 19 | 20 | * [Disnix](http://github.com/svanderburg/disnix) 21 | * [NixOps](http://github.com/nixos/nixops), if it is desired to use NixOps' infrastructure deployment facilities 22 | 23 | When building directly from a Git clone, you also need: 24 | 25 | * [help2man](https://www.gnu.org/software/help2man) 26 | * [doclifter](http://www.catb.org/esr/doclifter) 27 | 28 | These dependencies can be acquired with the Nix package manager, your host 29 | system's package manager or be compiled from sources. Consult the documentation 30 | of your distribution or the corresponding packages for more information. 31 | 32 | Installation 33 | ============ 34 | DisnixOS is a typical autotools based package which can be compiled and installed 35 | by running the following commands in a shell session: 36 | 37 | ```bash 38 | $ ./configure 39 | $ make 40 | $ make install 41 | ``` 42 | 43 | When building from the Git repository, you should run the bootstrap script 44 | first: 45 | 46 | ```bash 47 | $ ./bootstrap 48 | ``` 49 | 50 | For more information about using the autotools setup or for customizing the 51 | configuration, take a look at the `./INSTALL` file. 52 | 53 | Usage 54 | ===== 55 | DisnixOS supports various deployment operations. 56 | 57 | Deploying infrastructure 58 | ------------------------ 59 | In order to deploy infrastructure (i.e. a network of NixOS machines), one must 60 | create on or more NixOS network models that define a network of NixOS 61 | configurations. 62 | 63 | By running the following command-line instruction with at least one network model 64 | as a parameter, the system configuration will be deployed through Disnix: 65 | 66 | ```bash 67 | $ disnixos-deploy-network network.nix 68 | ``` 69 | 70 | Deploying services and infrastructure at the same time 71 | ------------------------------------------------------ 72 | Besides infrastructure only, we can also deploy services and infrastructure at 73 | the same time. For example: 74 | 75 | ```bash 76 | $ disnixos-env -s services.nix -n network.nix -d distribution.nix 77 | ``` 78 | 79 | The above command-line instruction first deploys the infrastructure and then 80 | the services using Disnix. The infrastructure model is generated automatically 81 | from the NixOS network model. 82 | 83 | Deploying services and infrastructure in a network of QEMU VMs 84 | -------------------------------------------------------------- 85 | We can also spawn a network of efficiently instantiated QEMU VMs in which a 86 | service-oriented system is deployed through Disnix: 87 | 88 | ```bash 89 | $ disnixos-vm-env -s services.nix -n network.nix -d distribution.nix 90 | ``` 91 | 92 | The above command uses NixOS' test driver to quickly set up VMs and is 93 | paricularly useful to quickly test a deployment. 94 | 95 | Deploying infrastructure through NixOps and services through Disnix 96 | ------------------------------------------------------------------ 97 | We can also use NixOps to instantiate and deploy infrastructure, and use 98 | Disnix to deploy the services to the corresponding VM instances. 99 | 100 | The following command instantiates and deploys a network of VirtualBox machines: 101 | 102 | ```bash 103 | $ nixops create ./network.nix ./network-virtualbox.nix -d test 104 | $ nixops deploy -d test 105 | ``` 106 | 107 | The following environment variable specifies that we want to deploy in a network 108 | called `test` that is deployed by NixOps: 109 | 110 | ```bash 111 | $ export NIXOPS_DEPLOYMENT=test 112 | ``` 113 | 114 | The following command deploys the services into the network deployed by NixOps: 115 | 116 | ```bash 117 | $ disnixos-env -s services.nix -n network.nix -n network-virtualbox.nix -d distribution.nix --use-nixops 118 | ``` 119 | 120 | Automated testing of Disnix deployments 121 | --------------------------------------- 122 | Another feature of this package are function abstractions that can be used to 123 | non-interactively test a Disnix deployment from within a Nix build for testing 124 | purposes. Consult the manual for more details on this. 125 | 126 | Manual 127 | ====== 128 | DisnixOS has a nice Docbook manual that can be compiled yourself. However, it is 129 | also available [online](http://hydra.nixos.org/job/disnix/disnixos-trunk/tarball/latest/download-by-type/doc/manual). 130 | 131 | License 132 | ======= 133 | DisnixOS is free software; you can redistribute it and/or modify it under the 134 | terms of the [GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html) 135 | as published by the [Free Software Foundation](http://www.fsf.org) either version 136 | 2.1 of the License, or (at your option) any later version. Disnix is distributed 137 | in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 138 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 139 | GNU Lesser General Public License for more details. 140 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f config.cache config.log acconfig.h aclocal.m4 README 4 | 5 | ln -s README.md README 6 | mkdir -p config 7 | autoreconf -fvi 8 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.61) 2 | AC_INIT([disnixos], m4_esyscmd([echo -n $(cat ./version)$VERSION_SUFFIX])) 3 | AC_CONFIG_AUX_DIR([config]) 4 | AM_INIT_AUTOMAKE([1.9 tar-pax -Wall -Werror -Wno-extra-portability]) 5 | 6 | # Checks for installed programs 7 | AC_DEFUN([NEED_PROG], 8 | [ 9 | AC_PATH_PROG($1, $2) 10 | if test -z "$$1"; then 11 | AC_MSG_ERROR([$2 is required]) 12 | fi 13 | ]) 14 | 15 | # Checks for programs 16 | AC_PROG_INSTALL 17 | PKG_PROG_PKG_CONFIG 18 | NEED_PROG(socat, socat) 19 | NEED_PROG(getopt, getopt) 20 | NEED_PROG(dysnomia, dysnomia) 21 | AC_PATH_PROG(xmllint, xmllint, false) 22 | AC_PATH_PROG(xsltproc, xsltproc, false) 23 | AC_PATH_PROG(dblatex, dblatex) 24 | AC_PATH_PROG(HELP2MAN, help2man, false) 25 | AC_PATH_PROG(DOCLIFTER, doclifter, false) 26 | 27 | # Checks for Docbook stuff 28 | AC_ARG_WITH(docbook-rng, AC_HELP_STRING([--with-docbook-rng=PATH], 29 | [path of the DocBook RelaxNG schema]), 30 | docbookrng=$withval, docbookrng=/docbook-rng-missing) 31 | AC_SUBST(docbookrng) 32 | 33 | AC_ARG_WITH(docbook-xsl, AC_HELP_STRING([--with-docbook-xsl=PATH], 34 | [path of the DocBook XSL stylesheets]), 35 | docbookxsl=$withval, docbookxsl=/docbook-xsl-missing) 36 | AC_SUBST(docbookxsl) 37 | 38 | # Checks for Disnix libraries 39 | DISNIX_REQUIRED=0.10 40 | PKG_CHECK_MODULES(DISNIX, disnix >= $DISNIX_REQUIRED) 41 | DISNIX_PREFIX=`pkg-config --variable=prefix disnix` 42 | AC_SUBST(DISNIX_PREFIX) 43 | 44 | # Output 45 | AC_CONFIG_FILES([ 46 | Makefile 47 | doc/Makefile 48 | doc/manual/Makefile 49 | scripts/Makefile 50 | nix/Makefile 51 | nix/generate-infrastructure.nix 52 | nix/generate-tests.nix 53 | nix/testing.nix 54 | maintenance/Makefile 55 | scripts/disnix-backdoor-client 56 | scripts/disnix-nixops-client 57 | scripts/disnixos-instantiate 58 | scripts/disnixos-manifest 59 | scripts/disnixos-deploy-network 60 | scripts/disnixos-delegate 61 | scripts/disnixos-env 62 | scripts/disnixos-geninfra 63 | scripts/disnixos-gentests 64 | scripts/disnixos-vm-env 65 | scripts/disnixos-collect-garbage 66 | scripts/disnixos-clean-snapshots 67 | scripts/disnixos-query 68 | scripts/disnixos-snapshot-network 69 | scripts/disnixos-restore-network 70 | scripts/disnixos-delete-network-state 71 | scripts/disnixos-capture-manifest 72 | scripts/disnixos-reconstruct 73 | scripts/disnixos-convert-manifest 74 | scripts/disnixos-convert 75 | ]) 76 | AC_OUTPUT 77 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = manual 2 | -------------------------------------------------------------------------------- /doc/manual/Makefile.am: -------------------------------------------------------------------------------- 1 | XMLLINT = $(xmllint) 2 | XSLTPROC = $(xsltproc) \ 3 | --param section.autolabel 1 \ 4 | --param section.label.includes.component.label 1 \ 5 | --param html.stylesheet \'style.css\' \ 6 | --param make.valid.html 1 \ 7 | --param xref.with.number.and.title 1 \ 8 | --param toc.section.depth 3 \ 9 | --param admon.style \'\' \ 10 | --param callout.graphics.extension \'.gif\' \ 11 | --param contrib.inline.enabled 0 12 | 13 | dblatex_opts = \ 14 | -P doc.collab.show=0 \ 15 | -P latex.output.revhistory=0 16 | 17 | MANUAL_SRCS = index.xml introduction.xml background.xml installation.xml images style.css 18 | 19 | version.txt: 20 | echo -n $(VERSION) > version.txt 21 | 22 | # Note: RelaxNG validation requires xmllint >= 2.7.4. 23 | manual.is-valid: $(MANUAL_SRCS) version.txt 24 | $(XMLLINT) --noout --nonet --xinclude --noxincludenode --relaxng $(docbookrng)/docbook.rng $< 25 | touch $@ 26 | 27 | index.html: $(MANUAL_SRCS) manual.is-valid images 28 | $(XSLTPROC) --nonet --xinclude --output index.html \ 29 | $(docbookxsl)/html/docbook.xsl index.xml 30 | 31 | index.pdf: $(MANUAL_SRCS) manual.is-valid images 32 | if test "$(dblatex)" != ""; then \ 33 | $(dblatex) $(dblatex_opts) index.xml; \ 34 | else \ 35 | echo "Please install dblatex and rerun configure."; \ 36 | exit 1; \ 37 | fi 38 | 39 | images: 40 | mkdir images 41 | mkdir images/callouts 42 | cp $(docbookxsl)/images/callouts/*.gif images/callouts 43 | chmod -R +w images 44 | 45 | all-local: index.html 46 | 47 | install-data-local: index.html 48 | $(INSTALL) -d $(DESTDIR)$(docdir)/manual 49 | $(INSTALL_DATA) index.html $(DESTDIR)$(docdir)/manual 50 | $(INSTALL_DATA) style.css $(DESTDIR)$(docdir)/manual 51 | cp -r images $(DESTDIR)$(docdir)/manual/images 52 | 53 | KEEP = index.html manual.is-valid version.txt 54 | 55 | EXTRA_DIST = $(MANUAL_SRCS) $(FIGURES) $(KEEP) 56 | 57 | DISTCLEANFILES = $(KEEP) 58 | -------------------------------------------------------------------------------- /doc/manual/background.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | Background 6 | 7 | 8 | NixOS 9 | is a GNU/Linux distribution using the Nix package manager to manage 10 | all packages, system components (such as the Linux kernel) and configuration files. 11 | In NixOS, system configurations are derived from declarative specifications describing 12 | properties of the system, such as kernel modules, partitions, services and 13 | system packages. 14 | 15 | 16 | 17 | A NixOS configuration running a OpenSSH server 18 | 19 | {pkgs, ...}: 20 | 21 | { 22 | boot = { 23 | loader = { 24 | grub = { 25 | device = "/dev/sda"; 26 | }; 27 | }; 28 | }; 29 | 30 | fileSystems = [ 31 | { mountPoint = "/"; 32 | device = "/dev/sda2"; 33 | } 34 | ]; 35 | 36 | swapDevices = [ 37 | { device = "/dev/sda1"; } 38 | ]; 39 | 40 | services = { 41 | openssh = { 42 | enable = true; 43 | }; 44 | }; 45 | 46 | environment = { 47 | systemPackages = [ 48 | pkgs.mc 49 | pkgs.subversion 50 | pkgs.lynx 51 | ]; 52 | }; 53 | } 54 | 55 | 56 | 57 | 58 | shows a Nix expression describing the configuration 59 | of a machine. 60 | 61 | 62 | 63 | 64 | 65 | This line states that the expression is a function, having 66 | an argument called pkgs, which refers to 67 | Nixpkgs, 68 | a collection of 2500 packages that can be deployed 69 | by the Nix package manager. 70 | 71 | 72 | 73 | 74 | 75 | This section of the NixOS specification describes the settings 76 | of the GRUB bootloader, such as that the partition containing 77 | the MBR is /dev/sda. 78 | 79 | 80 | 81 | 82 | 83 | This section of the NixOS specification describes the settings 84 | of hard drive partitions, such as the root partition and the 85 | swap partition. 86 | 87 | 88 | 89 | 90 | 91 | This section of the NixOS specification describes the services 92 | running on the system, such as the OpenSSH server providing 93 | remote SSH access. 94 | 95 | 96 | 97 | 98 | 99 | This section of the NixOS specification describes the system packages, 100 | which can be used by all users on the machines, such as the 101 | Lynx web browser and Midnight Commander. 102 | 103 | 104 | 105 | 106 | 107 | The specification in should be stored in the 108 | following location: /etc/nixos/configuration.nix. 109 | The complete configuration can be deployed by running: 110 | 111 | 112 | 113 | $ nixos-rebuild switch 114 | 115 | 116 | 117 | NixOS configurations can also be used in an attribute set, describing a network 118 | of machines: 119 | 120 | 121 | 122 | A network of NixOS configurations 123 | 124 | { 125 | test1 = import ../configurations/openssh.nix; 126 | test2 = import ../configurations/tomcat.nix; 127 | test3 = import ../configurations/httpd.nix; 128 | } 129 | 130 | 131 | 132 | 133 | shows a network of NixOS configurations. Basically, this 134 | expression is an attribute set in which each attribute refers to a NixOS configuration: 135 | 136 | 137 | 138 | 139 | 140 | This attribute declares that we have a machine with identifier 141 | test1, having a configuration running a OpenSSH server, 142 | described earlier in . 143 | 144 | 145 | 146 | 147 | This attribute declares that we have a machine with identifier 148 | test2, having a configuration running an Apache Tomcat server. 149 | 150 | 151 | 152 | 153 | 154 | By typing the following instruction on the command line, the network of machines are built 155 | from source code, distributed to the target machines and finally activated: 156 | 157 | 158 | 159 | $ disnixos-deploy-network network.nix 160 | 161 | 162 | 163 | In distributed environments, there are several more advanced features that may be desired to use. 164 | For example, each individual machine configuration has properties that are portable among any machine (such 165 | as the system services and end-user packages to run) and 166 | some properties are machine dependent, such as the partitions and boot loader settings. 167 | Moreover, system configurations may also have dependencies on other machines in the network. 168 | 169 | 170 | NixOS network models also allow to separate machine configuration aspects in seperate files and 171 | to allow one machine configuration to refer to another. 172 | The following example shows a more advanced configuration capturing the logical aspects of machines 173 | in a network. Furthermore, the system configurations have references to each other: 174 | 175 | 176 | 177 | A logical NixOS network model 178 | 179 | { 180 | tomcat = {pkgs, ...}: 181 | 182 | { 183 | services = { 184 | openssh = { 185 | enable = true; 186 | }; 187 | 188 | tomcat = { 189 | enable = true; 190 | }; 191 | }; 192 | }; 193 | 194 | httpd = {pkgs, nodes, ...}: 195 | 196 | { 197 | services = { 198 | openssh = { 199 | enable = true; 200 | }; 201 | 202 | httpd = { 203 | enable = true; 204 | adminAddr = "admin@example.com"; 205 | extraModules = [ "proxy_balancer "]; 206 | extraConfig = '' 207 | <Proxy balancer://cluster> 208 | Allow from all 209 | BalancerMember http://${nodes.tomcat.config.networking.hostName}:8080 retry=0 210 | </Proxy> 211 | 212 | ProxyStatus full 213 | ProxyPass /server-status ! 214 | ProxyPass / balancer://cluster/ 215 | ProxyPassReverse / balancer://cluster/ 216 | ''; 217 | }; 218 | }; 219 | }; 220 | 221 | } 222 | 223 | 224 | 225 | 226 | The model in is an attribute set in which each value refers to a 227 | NixOS configuration: 228 | 229 | 230 | 231 | 232 | 233 | The tomcat machine is a simple configuration hosting Apache Tomcat serving 234 | an arbitrary number of web applications, and an OpenSSH server. 235 | 236 | 237 | 238 | 239 | The httpd machine runs a reverse proxy that forwards all incoming requests to the Apache Tomcat server. 240 | It fetches the hostname of the tomcat machine's configuration through the nodes 241 | parameter. 242 | 243 | 244 | 245 | 246 | 247 | The logical network model above only captures machine independent properties and can be used in combination with a physical network model, capturing 248 | machine specific properties, such as the partitions and bootloader settings: 249 | 250 | 251 | 252 | A physical NixOS network model 253 | 254 | { 255 | tomcat = {pkgs, ...}: 256 | 257 | { 258 | boot = { 259 | loader = { 260 | grub = { 261 | device = "/dev/sda"; 262 | }; 263 | }; 264 | }; 265 | 266 | fileSystems = [ 267 | { mountPoint = "/"; 268 | device = "/dev/sda2"; 269 | } 270 | ]; 271 | 272 | swapDevices = [ 273 | { device = "/dev/sda1"; } 274 | ]; 275 | }; 276 | 277 | httpd = {pkgs, ...}: 278 | 279 | { 280 | boot = { 281 | loader = { 282 | grub = { 283 | device = "/dev/sda"; 284 | }; 285 | }; 286 | }; 287 | 288 | fileSystems = [ 289 | { mountPoint = "/"; 290 | device = "/dev/sda3"; 291 | } 292 | ]; 293 | 294 | swapDevices = [ 295 | { device = "/dev/sda2"; } 296 | ]; 297 | }; 298 | } 299 | 300 | 301 | 302 | 303 | The network in model shown in captures machine-specific properties, such as partition and bootloader 304 | settings. With the following command the network can be deployed taking both the given logical and physical 305 | properties into account: 306 | 307 | 308 | 309 | $ disnixos-deploy-network network-logical.nix network-physical.nix 310 | 311 | 312 | 313 | Disnix is a toolset supporting the deployment of services. DisnixOS combines the latter feature 314 | of using disnixos-deploy-network to deploy networks of NixOS machines, 315 | as addition to Disnix to provide infrastructure deployment. 316 | 317 | 318 | 319 | Physical network models can also refer to virtual machine properties hosted in an IaaS environment, such as Amazon EC2. 320 | If DisnixOS is used with NixOps, these machines can be automatically instantiated and deployed as well. Consult 321 | the NixOps manual for more details on VM instantiation and provisioning. 322 | 323 | 324 | -------------------------------------------------------------------------------- /doc/manual/index.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | DisnixOS User's Guide 6 | 7 | Draft (Version ) 8 | 9 | 10 | 11 | Sander 12 | van der Burg 13 | 14 | Author 15 | 16 | 17 | 18 | 2010 19 | 2011 20 | 2012 21 | 2013 22 | 2014 23 | 2015 24 | 2016 25 | 2017 26 | 2018 27 | 2019 28 | 2020 29 | 2021 30 | 2022 31 | Sander van der Burg 32 | 33 | 34 | September 2019 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Command Reference 44 | 45 |
46 | Main commands 47 | 48 | 49 | 50 |
51 | 52 |
53 | Utilities 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 |
75 |
76 | -------------------------------------------------------------------------------- /doc/manual/installation.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | Installation 6 | 7 | 8 | This chapter explains how DisnixOS can be installed. Apart from the basic 9 | Disnix 10 | toolset, only the coordinator machine needs the DisnixOS 11 | extension tools. 12 | 13 | 14 |
15 | Compiling DisnixOS from source 16 | 17 | 18 | This section explains how to compile DisnixOS from source code. 19 | Usually, this is only needed in special circumstances such as for 20 | development, or trying a new platform. A more convenient way to install 21 | DisnixOS is to use the Nix package manager. 22 | 23 | 24 |
25 | Prerequisites 26 | 27 | In order to build DisnixOS from source code, the following dependencies are required: 28 | Since it is an extension to 29 | Disnix, 30 | the core Disnix toolset must be installed. Have a look for 31 | installation instructions in the Disnix manual. 32 | Moreover, for network communication with the NixOS test driver, DisnixOS uses 33 | socat, 34 | which must also be present on the system. 35 | For infrastructure instantiation and provisioning, 36 | NixOps 37 | must be installed. Have a look at the NixOps manual 38 | for more information. 39 | 40 |
41 | 42 |
43 | Compiling DisnixOS 44 | 45 | 46 | After unpacking or checking out the DisnixOS sources, it can be 47 | compiled by executing the following commands: 48 | 49 | 50 | $ ./configure options... 51 | $ make 52 | $ make install 53 | 54 | 55 | 56 | 57 | When building from the Git repository, these should be 58 | preceded by the command: 59 | 60 | 61 | $ ./bootstrap 62 | 63 | 64 | 65 | 66 | The installation path can be specified by passing the 67 | to 68 | configure. The default installation directory is 69 | /usr/local. You can change this to any location 70 | you like. You must have write permission to the 71 | prefix path. 72 | 73 |
74 |
75 | 76 |
77 | Installing DisnixOS by using the Nix package manager 78 | 79 | 80 | The easiest way to use DisnixOS is by installing the DisnixOS package with 81 | the Nix package manager from the 82 | Nixpkgs 83 | repository by typing: 84 | 85 | 86 | $ nix-env -i disnixos 87 | 88 | 89 | Another way is downloading the DisnixOS source distribution 90 | and to compile it manually. Moreover, it is also a good thing to have 91 | to basic Disnix toolset in your environment. This can be done by typing: 92 | 93 | 94 | 95 | $ nix-env -i disnix 96 | 97 |
98 |
99 | -------------------------------------------------------------------------------- /doc/manual/introduction.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | Introduction 6 | 7 | 8 | Disnix is a distributed service deployment toolset which main 9 | purpose is to deploy service oriented systems (i.e. systems that can be 10 | decomposed into "distributable units") into networks of machines 11 | having various characteristics (such as operating systems) and is built on top of Nix; 12 | a package manager which has some unique features compared to conventional package 13 | managers to make deployment safe and reliable. 14 | 15 | 16 | 17 | The purpose of Disnix is to manage the deployment of distributable application 18 | components (or services) in a network of machines. Application 19 | components can be anything ranging from web services, web applications, databases, 20 | and ordinary processes. 21 | 22 | 23 | Disnix, however, expects the underlying infrastructure, such as machines running 24 | certain kinds of operating systems with certain containers (e.g. a DBMS or application server) to 25 | be present already. It does not manage the deployment of the infrastructure and their 26 | system configurations. Normally, a system administrator must manually install machines in the network 27 | having the required characteristics by following the installation steps of the operating system. 28 | 29 | 30 | Moreover, a system administrator or developer must manually write an infrastructure model, matching the 31 | actual configuration of the network in order to correctly deploy a service-oriented 32 | system, which may be a lot of work and error prone. 33 | 34 | 35 | 36 | This DisnixOS extension provides complementary infrastructure management tools for Disnix 37 | built on top of 38 | NixOS, 39 | a GNU/Linux distribution built around the Nix package manager. NixOS is a distribution 40 | in which complete system configurations can be built from declarative specifications and 41 | supports atomic upgrades and rollbacks of complete system configurations. 42 | 43 | 44 |
45 | Features 46 | 47 | 48 | DisnixOS adds the following features to the basic Disnix toolset: 49 | 50 | 51 | Infrastructure deployment 52 | 53 | DisnixOS allows you to write a network of NixOS configurations in a model and 54 | to automatically deploy the system configurations in a network of machines through 55 | their Disnix interfaces. 56 | 57 | 58 | 59 | 60 | Infrastructure virtualisation 61 | 62 | DisnixOS uses the NixOS test driver to build a network of virtual machines 63 | closely matching the actual network and automatically deploys the service-oriented system 64 | in the virtual network, so that it can be easily tested by developers. 65 | 66 | 67 | 68 | 69 | Automated testing of a service-oriented system 70 | 71 | DisnixOS uses the NixOS test driver techniques, used for the NixOS 72 | testsuite, to automatically script the deployment and testcases in a distributed 73 | environment, so that a service-oriented system can be automatically tested, and run on 74 | Hydra, 75 | a continuous build and integration server built on top of Nix. 76 | 77 | 78 | 79 | 80 | Infrastructure instantiation and provisioning 81 | 82 | DisnixOS can also be used in combination with NixOps, 83 | a tool that deploys networks of NixOS configurations and automatically instantiate and provisions 84 | virtual machines in an IaaS environment, such as Amazon EC2. 85 | 86 | 87 |
88 |
89 | -------------------------------------------------------------------------------- /doc/manual/style.css: -------------------------------------------------------------------------------- 1 | body 2 | { 3 | font-family: arial, lucida, helvetica, sans-serif; 4 | font-size: 100%; 5 | } 6 | 7 | h1 8 | { 9 | color: #0055aa; 10 | font-size: 170%; 11 | } 12 | 13 | h2 14 | { 15 | font-size: 150%; 16 | } 17 | 18 | h3 19 | { 20 | font-size: 125%; 21 | } 22 | 23 | pre.screen, pre.programlisting 24 | { 25 | border-style: solid; 26 | border-width: 1px; 27 | background-color: #dddddd; 28 | padding: 0.5em; 29 | } 30 | -------------------------------------------------------------------------------- /maintenance/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = man2docbook.bash 2 | -------------------------------------------------------------------------------- /maintenance/man2docbook.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Usage: $0 command.section 3 | 4 | param=$1 5 | command=${param:0:-2} 6 | section=${param: -1} 7 | id=$(echo $command | sed "s/-//g") 8 | 9 | doclifter -x $param 10 | 11 | sed -i -e "s|©|(C)|" \ 12 | -e "s|xml:id='$id$section'|xml:id='sec-$command'|" \ 13 | -e "s|xml:id='synopsis'||" \ 14 | -e "s|xml:id='description'||" \ 15 | -e "s|xml:id='options'||" \ 16 | -e "s|xml:id='environment'||" \ 17 | -e "s|xml:id='copyright'||" \ 18 | -e "s|xml:id='operations'||" \ 19 | -e "s|xml:id='general_options'||" \ 20 | -e "s|xml:id='importexportimport_snapshotsexport_snaps'||" \ 21 | -e "s|xml:id='setquery_installedlockunlock_options'||" \ 22 | -e "s|xml:id='collect_garbage_options'||" \ 23 | -e "s|xml:id='activationdeactivationsnapshotrestoredel'||" \ 24 | -e "s|xml:id='query_all_snapshotsquery_latest_snapshot'||" \ 25 | -e "s|xml:id='clean_snapshots_options'||" \ 26 | -e "s|${command^^}|$command|" \ 27 | $command.$section.xml 28 | -------------------------------------------------------------------------------- /nix/Makefile.am: -------------------------------------------------------------------------------- 1 | pkgdata_DATA = generate-infrastructure.nix generate-tests.nix infrastructure.nix.in testing.nix lib.nix manifest.nix instantiate.nix disnix-infrastructure-module.nix generate-testscript.nix generate-manifest.nix generate-distributed-derivation.nix 2 | EXTRA_DIST = generate-infrastructure.nix.in generate-tests.nix.in infrastructure.nix.in testing.nix.in lib.nix manifest.nix instantiate.nix disnix-infrastructure-module.nix generate-testscript.nix generate-manifest.nix generate-distributed-derivation.nix 3 | -------------------------------------------------------------------------------- /nix/disnix-infrastructure-module.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | cfg = config.disnixInfrastructure; 5 | in 6 | { 7 | options = { 8 | disnixInfrastructure = { 9 | enable = lib.mkOption { 10 | default = false; 11 | description = "Whether to enable infrastructure publishing"; 12 | }; 13 | 14 | enableAuthentication = lib.mkOption { 15 | default = false; 16 | description = "Whether to publish authentication credentials through the infrastructure attribute (not recommended in combination with Avahi)"; 17 | }; 18 | 19 | infrastructure = lib.mkOption { 20 | default = {}; 21 | description = "An attribute set containing infrastructure model properties"; 22 | }; 23 | 24 | properties = lib.mkOption { 25 | default = {}; 26 | description = "An attribute set container arbitary machine properties"; 27 | }; 28 | 29 | generateContainersExpr = lib.mkOption { 30 | description = "The path to the expression generating the container properties"; 31 | type = lib.types.path; 32 | }; 33 | }; 34 | }; 35 | 36 | config = lib.mkIf cfg.enable { 37 | disnixInfrastructure.infrastructure = { 38 | properties = { 39 | hostname = config.networking.hostName; 40 | } // cfg.properties; 41 | 42 | system = if config.nixpkgs ? localSystem && config.nixpkgs.localSystem.system != "" then config.nixpkgs.localSystem.system # Support compatiblity with Nixpkgs 17.09 and newer versions 43 | else if config.nixpkgs.system != "" then config.nixpkgs.system 44 | else builtins.currentSystem; 45 | 46 | containers = lib.recursiveUpdate (import cfg.generateContainersExpr { 47 | inherit (cfg) enableAuthentication; 48 | inherit config lib; 49 | }) (config.dysnomia.extraContainerProperties or {}); 50 | }; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /nix/generate-distributed-derivation.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, pkgs}: 2 | 3 | /* 4 | * Generates a distributed derivation file constisting of a mapping of store derivations 5 | * to machines from the 3 Disnix models. 6 | * 7 | * Parameters: 8 | * network: An evaluated network with machine configurations 9 | * targetProperty: Attribute from the infrastructure model that is used to connect to the Disnix interface 10 | * clientInterface: Path to the executable used to connect to the Disnix interface 11 | * enableDisnix: Indicates whether Disnix must be enabled 12 | * nixOpsModel: Indicates whether we should use NixOps specific settings 13 | * useVMTesting: Indicates whether we should enable NixOS test instrumentation and VM settings 14 | * useBackdoor: Indicates whether we should enable the backdoor 15 | * dysnomia: Path to Dysnomia 16 | * nixops: Path to NixOps 17 | * 18 | * Returns: 19 | * An attributeset which should be exported to XML representing the distributed derivation 20 | */ 21 | {network, targetProperty, clientInterface, enableDisnix, nixOpsModel, useVMTesting, useBackdoor, dysnomia, nixops}: 22 | 23 | let 24 | inherit (builtins) getAttr unsafeDiscardOutputDependency; 25 | 26 | lib = import ./lib.nix { 27 | inherit nixpkgs pkgs; 28 | }; 29 | 30 | configurations = lib.generateConfigurations { 31 | inherit network enableDisnix nixOpsModel useVMTesting useBackdoor dysnomia nixops; 32 | }; 33 | 34 | getTargetProperty = targetProperty: target: 35 | if target ? targetProperty then getAttr (target.targetProperty) target 36 | else getAttr targetProperty target; 37 | in 38 | { 39 | derivationMappings = pkgs.lib.mapAttrs (targetName: machine: 40 | let 41 | infrastructure = machine.config.disnixInfrastructure.infrastructure; 42 | in 43 | unsafeDiscardOutputDependency (machine.config.system.build.toplevel.drvPath) 44 | ) configurations; 45 | 46 | interfaces = pkgs.lib.mapAttrs (targetName: machine: 47 | let 48 | infrastructure = machine.config.disnixInfrastructure.infrastructure; 49 | in 50 | { targetAddress = getTargetProperty targetProperty infrastructure; 51 | clientInterface = if infrastructure ? clientInterface then infrastructure.clientInterface else clientInterface; 52 | } 53 | ) configurations; 54 | } 55 | -------------------------------------------------------------------------------- /nix/generate-infrastructure.nix.in: -------------------------------------------------------------------------------- 1 | { networkFiles 2 | , useBackdoor ? false 3 | , useVMTesting ? false 4 | , enableDisnix ? true 5 | , nixOpsModel ? false 6 | , nixpkgs ? 7 | , dysnomia 8 | , nixops ? null 9 | }: 10 | 11 | let 12 | pkgs = import nixpkgs {}; 13 | infrastructureNix = ./infrastructure.nix.in; 14 | in 15 | pkgs.stdenv.mkDerivation { 16 | name = "infrastructure.nix"; 17 | buildCommand = '' 18 | sed -e "s|@networkFiles@|${toString networkFiles}|" \ 19 | -e "s|@nixpkgs@|${nixpkgs}|" \ 20 | -e "s|@useBackdoor@|${if useBackdoor then "true" else "false"}|" \ 21 | -e "s|@useVMTesting@|${if useVMTesting then "true" else "false"}|" \ 22 | -e "s|@enableDisnix@|${if enableDisnix then "true" else "false"}|" \ 23 | -e "s|@nixOpsModel@|${if nixOpsModel then "true" else "false"}|" \ 24 | -e "s|@disnixos@|${builtins.storePath @prefix@}|" \ 25 | -e "s|@dysnomia"@"|${builtins.storePath dysnomia}|" \ 26 | -e "s|@nixops@|${if nixops == null then "null" else "builtins.storePath ${builtins.storePath nixops}"}|" \ 27 | -e "s|@PACKAGE"@"|@PACKAGE@|" \ 28 | ${infrastructureNix} > $out 29 | ''; 30 | } 31 | -------------------------------------------------------------------------------- /nix/generate-manifest.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, pkgs}: 2 | 3 | let 4 | lib = import ./lib.nix { 5 | inherit nixpkgs pkgs; 6 | }; 7 | 8 | inherit (builtins) attrNames getAttr hashString listToAttrs stringLength substring toXML unsafeDiscardStringContext; 9 | 10 | generateHash = {name, type, pkg, dependsOn}: 11 | unsafeDiscardStringContext (hashString "sha256" (toXML { 12 | inherit name type pkg dependsOn; 13 | })); 14 | in 15 | /* 16 | * Generates a manifest file consisting of a profile mapping and 17 | * service activation mapping from the 3 Disnix models. 18 | * 19 | * Parameters: 20 | * network: An evaluated network with machine configurations 21 | * targetProperty: Attribute from the infrastructure model that is used to connect to the Disnix interface 22 | * clientInterface: Path to the executable used to connect to the Disnix interface 23 | * enableDisnix: Indicates whether Disnix must be enabled 24 | * nixOpsModel: Indicates whether we should use NixOps specific settings 25 | * useVMTesting: Indicates whether we should enable NixOS test instrumentation and VM settings 26 | * useBackdoor: Indicates whether we should enable the backdoor 27 | * dysnomia: Path to Dysnomia 28 | * nixops: Path to NixOps 29 | * 30 | * Returns: 31 | * An attributeset which should be exported to XML representing the manifest 32 | */ 33 | 34 | {network, targetProperty, clientInterface, enableDisnix, nixOpsModel, useVMTesting, useBackdoor, dysnomia, nixops}: 35 | 36 | let 37 | configurations = lib.generateConfigurations { 38 | inherit network enableDisnix nixOpsModel useVMTesting useBackdoor dysnomia nixops; 39 | }; 40 | in 41 | { 42 | profiles = pkgs.lib.mapAttrs (targetName: machine: machine.config.system.build.toplevel.outPath) configurations; 43 | 44 | services = listToAttrs (map (targetName: 45 | let 46 | machine = getAttr targetName configurations; 47 | serviceConfig = { 48 | name = targetName; 49 | pkg = machine.config.system.build.toplevel.outPath; 50 | dependsOn = {}; 51 | type = "nixos-configuration"; 52 | }; 53 | in 54 | { name = generateHash serviceConfig; 55 | value = serviceConfig; 56 | } 57 | ) (attrNames configurations)); 58 | 59 | serviceMappings = map (targetName: 60 | let 61 | machine = getAttr targetName configurations; 62 | in 63 | { service = generateHash { 64 | name = targetName; 65 | pkg = machine.config.system.build.toplevel.outPath; 66 | dependsOn = {}; 67 | type = "nixos-configuration"; 68 | }; 69 | container = "nixos-configuration"; 70 | target = targetName; 71 | } 72 | ) (attrNames configurations); 73 | 74 | snapshotMappings = map (targetName: 75 | let 76 | machine = getAttr targetName configurations; 77 | pkg = machine.config.system.build.toplevel.outPath; 78 | in 79 | { service = generateHash { 80 | name = targetName; 81 | dependsOn = {}; 82 | type = "nixos-configuration"; 83 | inherit pkg; 84 | }; 85 | component = substring 33 (stringLength pkg) (baseNameOf pkg); 86 | container = "nixos-configuration"; 87 | target = targetName; 88 | } 89 | ) (attrNames configurations); 90 | 91 | infrastructure = pkgs.lib.mapAttrs (targetName: machine: 92 | let 93 | machine = getAttr targetName configurations; 94 | in 95 | { 96 | inherit targetProperty clientInterface; 97 | numOfCores = 1; 98 | } // machine.config.disnixInfrastructure.infrastructure 99 | ) configurations; 100 | } 101 | -------------------------------------------------------------------------------- /nix/generate-tests.nix.in: -------------------------------------------------------------------------------- 1 | { networkFiles 2 | , manifestFile 3 | , nixpkgs ? 4 | , disnix ? builtins.storePath @DISNIX_PREFIX@ 5 | , nixOpsModel ? false 6 | }: 7 | 8 | let 9 | pkgs = import nixpkgs {}; 10 | 11 | lib = import ./lib.nix { 12 | inherit pkgs nixpkgs; 13 | }; 14 | 15 | network = lib.generateMergedNetwork { 16 | inherit networkFiles nixOpsModel; 17 | }; 18 | 19 | testScript = import ./generate-testscript.nix { 20 | inherit network disnix manifestFile; 21 | inherit (pkgs) daemon socat libxml2; 22 | inherit (pkgs.lib) concatMapStrings; 23 | testScript = '' 24 | import time 25 | 26 | while True: 27 | time.sleep(1) 28 | ''; 29 | }; 30 | in 31 | pkgs.stdenv.mkDerivation { 32 | name = "testScript"; 33 | buildCommand = '' 34 | cat > $out << "EOF" 35 | ${testScript} 36 | EOF 37 | ''; 38 | } 39 | -------------------------------------------------------------------------------- /nix/generate-testscript.nix: -------------------------------------------------------------------------------- 1 | {network, testScript, manifestFile, disnix, daemon, socat, libxml2, concatMapStrings, dysnomiaStateDir ? "/tmp/shared/dysnomia", postActivateTimeout ? 1}: 2 | 3 | let 4 | firstTargetName = builtins.head (builtins.attrNames network); 5 | in 6 | '' 7 | # fmt: off 8 | start_all() 9 | '' + concatMapStrings (targetName: '' 10 | ${targetName}.wait_for_unit("network.target") 11 | ${targetName}.wait_for_unit("disnix.service") 12 | ${targetName}.succeed("iptables -I INPUT -p tcp --dport 512 -j ACCEPT || true") 13 | ${targetName}.succeed( 14 | "${daemon}/bin/daemon --unsafe --pidfile /run/socat-backdoor.pid -- ${socat}/bin/socat tcp-listen:512,fork exec:/bin/sh" 15 | ) 16 | ${targetName}.wait_for_file("/run/socat-backdoor.pid") 17 | ${targetName}.succeed("mkdir -p /var/state/dysnomia") 18 | ${targetName}.succeed( 19 | 'if [ -d "${dysnomiaStateDir}/snapshots" ]; then ln -s ${dysnomiaStateDir}/snapshots /var/state/dysnomia/snapshots; fi' 20 | ) 21 | ${targetName}.succeed( 22 | 'if [ -d "${dysnomiaStateDir}/generations" ]; then ln -s ${dysnomiaStateDir}/generations /var/state/dysnomia/generations; fi' 23 | ) 24 | 25 | # Create profile symlink 26 | 27 | profile = ${targetName}.succeed( 28 | "${libxml2}/bin/xmllint --xpath \"/manifest/profiles/profile[@name='${targetName}']/text()\" ${manifestFile}" 29 | ) 30 | ${targetName}.succeed("mkdir -p /nix/var/nix/profiles/disnix") 31 | ${targetName}.succeed("ln -s {} /nix/var/nix/profiles/default".format(profile[:-1])) 32 | '') (builtins.attrNames network) + 33 | '' 34 | 35 | ${firstTargetName}.succeed( 36 | "${disnix}/bin/disnix-activate --no-upgrade ${manifestFile}" 37 | ) 38 | ${firstTargetName}.succeed("sleep ${toString postActivateTimeout}") 39 | ${firstTargetName}.succeed( 40 | "${disnix}/bin/disnix-restore --no-upgrade ${manifestFile}" 41 | ) 42 | 43 | # fmt: on 44 | '' + 45 | testScript 46 | -------------------------------------------------------------------------------- /nix/infrastructure.nix.in: -------------------------------------------------------------------------------- 1 | let 2 | networkFiles = [ @networkFiles@ ]; 3 | nixpkgs = builtins.storePath @nixpkgs@; 4 | disnixos = builtins.storePath @disnixos@; 5 | useBackdoor = @useBackdoor@; 6 | useVMTesting = @useVMTesting@; 7 | enableDisnix = @enableDisnix@; 8 | nixOpsModel = @nixOpsModel@; 9 | dysnomia = builtins.storePath @dysnomia@; 10 | nixops = @nixops@; 11 | 12 | pkgs = import nixpkgs {}; 13 | 14 | lib = import "${disnixos}/share/@PACKAGE@/lib.nix" { 15 | inherit nixpkgs pkgs; 16 | }; 17 | 18 | network = lib.generateMergedNetwork { 19 | inherit networkFiles nixOpsModel; 20 | }; 21 | 22 | configurations = lib.generateConfigurations { 23 | inherit network enableDisnix nixOpsModel useVMTesting useBackdoor dysnomia nixops; 24 | }; 25 | in 26 | pkgs.lib.mapAttrs (targetName: machine: machine.config.disnixInfrastructure.infrastructure) configurations 27 | -------------------------------------------------------------------------------- /nix/instantiate.nix: -------------------------------------------------------------------------------- 1 | { networkFiles 2 | , targetProperty 3 | , clientInterface 4 | , nixpkgs ? 5 | , enableDisnix ? true 6 | , nixOpsModel ? false 7 | , disnix 8 | , dysnomia 9 | , nixops ? null 10 | }: 11 | 12 | let 13 | pkgs = import nixpkgs {}; 14 | 15 | lib = import ./lib.nix { inherit nixpkgs pkgs; }; 16 | 17 | generateDistributedDerivation = import ./generate-distributed-derivation.nix { 18 | inherit nixpkgs pkgs; 19 | }; 20 | 21 | mergedNetwork = lib.generateMergedNetwork { 22 | inherit networkFiles nixOpsModel; 23 | }; 24 | 25 | distributedDerivation = generateDistributedDerivation { 26 | network = mergedNetwork; 27 | inherit targetProperty clientInterface enableDisnix nixOpsModel dysnomia nixops; 28 | useVMTesting = false; 29 | useBackdoor = false; 30 | }; 31 | 32 | generateDistributedDerivationXSL = "${disnix}/share/disnix/generatedistributedderivation.xsl"; 33 | in 34 | pkgs.stdenv.mkDerivation { 35 | name = "distributedDerivation.xml"; 36 | buildInputs = [ pkgs.libxslt ]; 37 | distributedDerivationXML = builtins.toXML distributedDerivation; 38 | passAsFile = [ "distributedDerivationXML" ]; 39 | 40 | buildCommand = '' 41 | if [ "$distributedDerivationXMLPath" != "" ] 42 | then 43 | xsltproc ${generateDistributedDerivationXSL} $distributedDerivationXMLPath > $out 44 | else 45 | ( 46 | cat < $out 50 | fi 51 | ''; 52 | } 53 | -------------------------------------------------------------------------------- /nix/lib.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, pkgs}: 2 | 3 | let 4 | evalConfig = import "${nixpkgs}/nixos/lib/eval-config.nix"; 5 | inherit (builtins) getAttr removeAttrs; 6 | in 7 | rec { 8 | /* 9 | * Takes a collection of NixOS network expressions and zips them into a list of 10 | * NixOS modules. 11 | * 12 | * Parameters: 13 | * networkFiles: A list of strings containing paths to NixOS network expressions 14 | * nixOpsModel: Indicates whether the configuration is a NixOps model so that certain attributes are ignored. 15 | * 16 | * Returns: 17 | * An attribute set in which the names refer to machine names and values to lists of NixOS modules 18 | */ 19 | generateMergedNetwork = {networkFiles, nixOpsModel}: 20 | let 21 | networks = map (networkFile: import networkFile) networkFiles; 22 | mergedNetwork = pkgs.lib.zipAttrs networks; 23 | in 24 | if nixOpsModel then removeAttrs mergedNetwork [ "network" "resources" ] else mergedNetwork; # A NixOps model has a reserved network attributes that cannot be machines 25 | 26 | /* 27 | * Takes a merged network configuration and evaluates them producing a config 28 | * attribute for each of them. 29 | * 30 | * Parameters: 31 | * enableDisnix: Indicates whether Disnix must be enabled 32 | * nixOpsModel: Indicates whether we should use NixOps specific settings 33 | * useVMTesting: Indicates whether we should enable NixOS test instrumentation and VM settings 34 | * useBackdoor: Indicates whether we should enable the backdoor 35 | * dysnomia: Path to Dysnomia 36 | * nixops: Path to NixOps 37 | * 38 | * Returns: 39 | * An attribute set with evaluated machine configuration properties 40 | */ 41 | generateConfigurations = {network, enableDisnix, nixOpsModel, useVMTesting, useBackdoor, dysnomia, nixops}: 42 | pkgs.lib.mapAttrs (targetName: configuration: 43 | evalConfig { 44 | modules = configuration ++ [ 45 | ./disnix-infrastructure-module.nix 46 | ] ++ [ 47 | { 48 | key = "disnix-infrastructure"; 49 | networking.hostName = pkgs.lib.mkOverride 900 targetName; 50 | disnixInfrastructure.enable = true; 51 | disnixInfrastructure.enableAuthentication = true; 52 | disnixInfrastructure.generateContainersExpr = "${dysnomia}/share/dysnomia/generate-containers.nix"; 53 | } 54 | ] 55 | ++ pkgs.lib.optional enableDisnix { 56 | key = "enable-disnix"; 57 | environment.systemPackages = [ dysnomia pkgs.disnix ]; 58 | } 59 | ++ pkgs.lib.optionals useVMTesting [ 60 | "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" 61 | "${nixpkgs}/nixos/modules/testing/test-instrumentation.nix" 62 | ] 63 | ++ pkgs.lib.optional useBackdoor { 64 | key = "backdoor"; 65 | disnixInfrastructure.properties.backdoor = "TCP:${targetName}:512"; 66 | } 67 | ++ pkgs.lib.optional nixOpsModel { 68 | key = "nixops-stuff"; 69 | # Make NixOps's deployment.* options available. 70 | require = [ "${nixops}/share/nix/nixops/options.nix" ]; 71 | # Provide a default hostname and deployment target equal 72 | # to the attribute name of the machine in the model. 73 | deployment.targetHost = pkgs.lib.mkOverride 900 targetName; 74 | environment.checkConfigurationOptions = false; # We assume that NixOps has already checked it 75 | }; 76 | extraArgs = { 77 | nodes = generateConfigurations { 78 | inherit network enableDisnix nixOpsModel useVMTesting useBackdoor dysnomia nixops; 79 | }; 80 | }; 81 | }) network; 82 | } 83 | -------------------------------------------------------------------------------- /nix/manifest.nix: -------------------------------------------------------------------------------- 1 | { networkFiles 2 | , targetProperty 3 | , clientInterface 4 | , nixpkgs ? 5 | , enableDisnix ? true 6 | , nixOpsModel ? false 7 | , useVMTesting ? false 8 | , useBackdoor ? false 9 | , disnix 10 | , dysnomia 11 | , nixops ? null 12 | }: 13 | 14 | let 15 | pkgs = import nixpkgs {}; 16 | 17 | lib = import ./lib.nix { inherit nixpkgs pkgs; }; 18 | 19 | generateManifest = import ./generate-manifest.nix { inherit nixpkgs pkgs; }; 20 | 21 | mergedNetwork = lib.generateMergedNetwork { 22 | inherit networkFiles nixOpsModel; 23 | }; 24 | 25 | manifest = generateManifest { 26 | network = mergedNetwork; 27 | inherit targetProperty clientInterface enableDisnix nixOpsModel useVMTesting useBackdoor dysnomia nixops; 28 | }; 29 | 30 | generateManifestXSL = "${disnix}/share/disnix/generatemanifest.xsl"; 31 | in 32 | pkgs.stdenv.mkDerivation { 33 | name = "manifest.xml"; 34 | buildInputs = [ pkgs.libxslt ]; 35 | manifestXML = builtins.toXML manifest; 36 | passAsFile = [ "manifestXML" ]; 37 | 38 | buildCommand = '' 39 | if [ "$manifestXMLPath" != "" ] 40 | then 41 | xsltproc ${generateManifestXSL} $manifestXMLPath > $out 42 | else 43 | ( 44 | cat < $out 48 | fi 49 | ''; 50 | } 51 | -------------------------------------------------------------------------------- /nix/testing.nix.in: -------------------------------------------------------------------------------- 1 | { nixpkgs ? 2 | , system ? builtins.currentSystem 3 | , dysnomia ? builtins.storePath "@dysnomia@/../.." 4 | , disnix ? builtins.storePath @DISNIX_PREFIX@ 5 | , disnixos ? builtins.storePath @prefix@ 6 | }: 7 | 8 | let 9 | pkgs = import nixpkgs {}; 10 | 11 | generateManifestSrc = 12 | {name, tarball}: 13 | 14 | pkgs.stdenv.mkDerivation { 15 | name = "${name}-manifest-src"; 16 | buildCommand = 17 | '' 18 | mkdir -p $out 19 | cd $out 20 | tar xfvj ${tarball}/tarballs/*.tar.bz2 --strip-components=1 21 | ''; 22 | }; 23 | in 24 | { 25 | sourceTarball = 26 | {name, version, src, officialRelease}: 27 | 28 | pkgs.releaseTools.sourceTarball { 29 | inherit name version src officialRelease; 30 | 31 | distPhase = 32 | '' 33 | mkdir ../$name 34 | rm -Rf `find . -name .svn` 35 | mv * ../$name 36 | cd .. 37 | mkdir -p $out/tarballs 38 | tar cfvj $out/tarballs/$name.tar.bz2 $name 39 | ''; 40 | }; 41 | 42 | buildManifest = 43 | {name, version, tarball, servicesFile, networkFile, externalNetworkFile ? false, distributionFile, extraParams ? {}, externalDistributionFile ? false}: 44 | 45 | let 46 | infrastructure = import ./generate-infrastructure.nix { 47 | networkFiles = [ (if externalNetworkFile then networkFile else "${manifestSrc}/${networkFile}") ]; 48 | useVMTesting = true; 49 | useBackdoor = true; 50 | inherit nixpkgs dysnomia; 51 | }; 52 | 53 | manifestSrc = generateManifestSrc { 54 | inherit name tarball; 55 | }; 56 | 57 | manifestModule = import "${disnix}/share/disnix/manifest.nix"; 58 | in 59 | pkgs.releaseTools.nixBuild { 60 | inherit name version; 61 | src = tarball; 62 | 63 | manifest = manifestModule.generateManifestFromModels { 64 | servicesFile = "${manifestSrc}/${servicesFile}"; 65 | infrastructureFile = "${infrastructure}"; 66 | distributionFile = if externalDistributionFile then distributionFile else "${manifestSrc}/${distributionFile}"; 67 | targetProperty = "backdoor"; 68 | clientInterface = "${disnixos}/bin/disnix-backdoor-client"; 69 | inherit nixpkgs extraParams; 70 | }; 71 | 72 | installPhase = 73 | '' 74 | mkdir -p $out 75 | ln -s $manifest $out/manifest.xml 76 | ''; 77 | 78 | checkPhase = "true"; 79 | }; 80 | 81 | disnixTest = 82 | {name, manifest, tarball, networkFile, externalNetworkFile ? false, testScript, dysnomiaStateDir ? "", postActivateTimeout ? 1}: 83 | 84 | let 85 | manifestSrc = generateManifestSrc { 86 | inherit name tarball; 87 | }; 88 | 89 | network = if externalNetworkFile then import networkFile else import "${manifestSrc}/${networkFile}"; 90 | in 91 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { inherit system; }; 92 | 93 | simpleTest { 94 | inherit name; 95 | nodes = network; 96 | 97 | testScript = import ./generate-testscript.nix { 98 | inherit network testScript disnix dysnomiaStateDir postActivateTimeout; 99 | inherit (pkgs) daemon socat libxml2; 100 | inherit (pkgs.lib) concatMapStrings; 101 | manifestFile = "${manifest}/manifest.xml"; 102 | }; 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? 2 | , systems ? [ "i686-linux" "x86_64-linux" ] 3 | , disnixos ? { outPath = ./.; rev = 1234; } 4 | , dysnomia ? { outPath = ../dysnomia; rev = 1234; } 5 | , disnix ? { outPath = ../disnix; rev = 1234; } 6 | , officialRelease ? false 7 | }: 8 | 9 | let 10 | pkgs = import nixpkgs {}; 11 | 12 | dysnomiaJobset = import "${dysnomia}/release.nix" { 13 | inherit nixpkgs systems officialRelease dysnomia; 14 | }; 15 | 16 | disnixJobset = import "${disnix}/release.nix" { 17 | inherit nixpkgs systems officialRelease dysnomia disnix; 18 | }; 19 | 20 | jobs = rec { 21 | tarball = 22 | let 23 | dysnomia = builtins.getAttr (builtins.currentSystem) (dysnomiaJobset.build); 24 | disnix = builtins.getAttr (builtins.currentSystem) (disnixJobset.build); 25 | in 26 | pkgs.releaseTools.sourceTarball { 27 | name = "disnixos-tarball"; 28 | version = builtins.readFile ./version; 29 | src = disnixos; 30 | inherit officialRelease; 31 | dontBuild = false; 32 | 33 | buildInputs = [ pkgs.socat pkgs.getopt pkgs.pkg-config pkgs.libxml2 pkgs.libxslt dysnomia disnix pkgs.dblatex (pkgs.dblatex.tex or pkgs.tetex) pkgs.help2man pkgs.doclifter pkgs.nukeReferences ]; 34 | 35 | # Add documentation in the tarball 36 | configureFlags = [ 37 | "--with-docbook-rng=${pkgs.docbook5}/xml/rng/docbook" 38 | "--with-docbook-xsl=${pkgs.docbook_xsl_ns}/xml/xsl/docbook" 39 | ]; 40 | 41 | preConfigure = '' 42 | # TeX needs a writable font cache. 43 | export VARTEXFONTS=$TMPDIR/texfonts 44 | ''; 45 | 46 | preDist = '' 47 | make -C doc/manual install prefix=$out 48 | 49 | make -C doc/manual index.pdf prefix=$out 50 | cp doc/manual/index.pdf $out/index.pdf 51 | 52 | # The PDF containes filenames of included graphics (see 53 | # http://www.tug.org/pipermail/pdftex/2007-August/007290.html). 54 | # This causes a retained dependency on dblatex, which Hydra 55 | # doesn't like (the output of the tarball job is distributed 56 | # to Windows and Macs, so there should be no Linux binaries 57 | # in the closure). 58 | nuke-refs $out/index.pdf 59 | 60 | echo "doc-pdf manual $out/index.pdf" >> $out/nix-support/hydra-build-products 61 | echo "doc manual $out/share/doc/disnixos/manual" >> $out/nix-support/hydra-build-products 62 | ''; 63 | }; 64 | 65 | build = 66 | pkgs.lib.genAttrs systems (system: 67 | let 68 | pkgs = import nixpkgs { inherit system; }; 69 | dysnomia = builtins.getAttr system (dysnomiaJobset.build); 70 | disnix = builtins.getAttr system (disnixJobset.build); 71 | in 72 | pkgs.releaseTools.nixBuild { 73 | name = "disnixos"; 74 | src = tarball; 75 | buildInputs = [ pkgs.socat pkgs.pkg-config dysnomia disnix pkgs.getopt ]; 76 | } 77 | ); 78 | 79 | tests = 80 | let 81 | dysnomia = builtins.getAttr (builtins.currentSystem) (dysnomiaJobset.build); 82 | disnix = builtins.getAttr (builtins.currentSystem) (disnixJobset.build); 83 | disnixos = builtins.getAttr (builtins.currentSystem) build; 84 | in 85 | { 86 | deploymentInfra = import ./tests/deployment-infra.nix { 87 | inherit nixpkgs dysnomia disnix disnixos; 88 | inherit (pkgs) writeTextFile openssh; 89 | }; 90 | 91 | deploymentInfraWithData = import ./tests/deployment-infra-with-data.nix { 92 | inherit nixpkgs dysnomia disnix disnixos; 93 | inherit (pkgs) writeTextFile runCommand openssh; 94 | dysnomiaTarball = dysnomiaJobset.tarball; 95 | }; 96 | 97 | distbuildInfra = import ./tests/distbuild-infra.nix { 98 | inherit nixpkgs dysnomia disnix disnixos; 99 | inherit (pkgs) writeTextFile openssh; 100 | }; 101 | 102 | deploymentServices = import ./tests/deployment-services.nix { 103 | inherit nixpkgs dysnomia disnix disnixos; 104 | inherit (pkgs) writeTextFile openssh; 105 | }; 106 | 107 | deploymentServicesWithData = import ./tests/deployment-services-with-data.nix { 108 | inherit nixpkgs dysnomia disnix disnixos; 109 | inherit (pkgs) writeTextFile openssh; 110 | }; 111 | 112 | distbuildServices = import ./tests/distbuild-services.nix { 113 | inherit nixpkgs dysnomia disnix disnixos; 114 | inherit (pkgs) writeTextFile openssh; 115 | }; 116 | 117 | nixopsClientToDBus = import ./tests/nixops-client.nix { 118 | inherit nixpkgs dysnomia disnix disnixos; 119 | inherit (pkgs) writeTextFile openssh; 120 | disnixRemoteClient = "disnix-client"; 121 | }; 122 | 123 | nixopsClientToRunActivity = import ./tests/nixops-client.nix { 124 | inherit nixpkgs dysnomia disnix disnixos; 125 | inherit (pkgs) writeTextFile openssh; 126 | disnixRemoteClient = "disnix-run-activity"; 127 | }; 128 | 129 | snapshotsViaDBus = import ./tests/snapshots.nix { 130 | inherit nixpkgs dysnomia disnix disnixos; 131 | inherit (pkgs) stdenv writeTextFile openssh; 132 | disnixRemoteClient = "disnix-client"; 133 | }; 134 | 135 | snapshotsViaRunActivity = import ./tests/snapshots.nix { 136 | inherit nixpkgs dysnomia disnix disnixos; 137 | inherit (pkgs) stdenv writeTextFile openssh; 138 | disnixRemoteClient = "disnix-run-activity"; 139 | }; 140 | 141 | deploymentNixOps = import ./tests/deployment-nixops.nix { 142 | inherit nixpkgs dysnomia disnix disnixos; 143 | inherit (pkgs) writeTextFile openssh; 144 | }; 145 | }; 146 | 147 | release = pkgs.releaseTools.aggregate { 148 | name = "disnixos-${tarball.version}"; 149 | constituents = [ 150 | tarball 151 | ] 152 | ++ map (system: builtins.getAttr system build) systems 153 | ++ [ 154 | tests.deploymentInfra 155 | tests.deploymentInfraWithData 156 | tests.distbuildInfra 157 | tests.deploymentServices 158 | tests.deploymentServicesWithData 159 | tests.distbuildServices 160 | tests.nixopsClientToDBus 161 | tests.nixopsClientToRunActivity 162 | tests.snapshotsViaDBus 163 | tests.snapshotsViaRunActivity 164 | tests.deploymentNixOps 165 | ]; 166 | meta.description = "Release-critical builds"; 167 | }; 168 | }; 169 | in jobs 170 | -------------------------------------------------------------------------------- /scripts/Makefile.am: -------------------------------------------------------------------------------- 1 | disnix-backdoor-client.1: disnix-backdoor-client.in 2 | $(HELP2MAN) --output=$@ --no-info --name 'Provides access to the disnix-service through a socket with public access' "$(SHELL) disnix-backdoor-client" 3 | 4 | disnix-backdoor-client.1.xml: disnix-backdoor-client.1 5 | $(SHELL) ../maintenance/man2docbook.bash $< 6 | 7 | disnix-nixops-client.1: disnix-nixops-client.in 8 | $(HELP2MAN) --output=$@ --no-info --name 'Provides access to the disnix-service through NixOps SSH interface' "$(SHELL) disnix-nixops-client" 9 | 10 | disnix-nixops-client.1.xml: disnix-nixops-client.1 11 | $(SHELL) ../maintenance/man2docbook.bash $< 12 | 13 | disnixos-geninfra.1: disnixos-geninfra.in 14 | $(HELP2MAN) --output=$@ --no-info --name 'Generate an infrastructure model from network models' "$(SHELL) disnixos-geninfra" 15 | 16 | disnixos-geninfra.1.xml: disnixos-geninfra.1 17 | $(SHELL) ../maintenance/man2docbook.bash $< 18 | 19 | disnixos-gentests.1: disnixos-gentests.in 20 | $(HELP2MAN) --output=$@ --no-info --name 'Generate initalialization steps of the test suite' "$(SHELL) disnixos-gentests" 21 | 22 | disnixos-gentests.1.xml: disnixos-gentests.1 23 | $(SHELL) ../maintenance/man2docbook.bash $< 24 | 25 | disnixos-instantiate.1: disnixos-instantiate.in 26 | $(HELP2MAN) --output=$@ --no-info --name 'Instantiate a distributed derivation from DisnixOS expressions' "$(SHELL) disnixos-instantiate" 27 | 28 | disnixos-instantiate.1.xml: disnixos-instantiate.1 29 | $(SHELL) ../maintenance/man2docbook.bash $< 30 | 31 | disnixos-manifest.1: disnixos-manifest.in 32 | $(HELP2MAN) --output=$@ --no-info --name 'Generate a manifest file from DisnixOS expressions' "$(SHELL) disnixos-manifest" 33 | 34 | disnixos-manifest.1.xml: disnixos-manifest.1 35 | $(SHELL) ../maintenance/man2docbook.bash $< 36 | 37 | disnixos-delegate.1: disnixos-delegate.in 38 | $(HELP2MAN) --output=$@ --no-info --name 'Delegates service and infrastructure builds to the target machines' "$(SHELL) disnixos-delegate" 39 | 40 | disnixos-delegate.1.xml: disnixos-delegate.1 41 | $(SHELL) ../maintenance/man2docbook.bash $< 42 | 43 | disnixos-env.1: disnixos-env.in 44 | $(HELP2MAN) --output=$@ --no-info --name 'Installs or updates the services and infrastructure of a distributed system' "$(SHELL) disnixos-env" 45 | 46 | disnixos-env.1.xml: disnixos-env.1 47 | $(SHELL) ../maintenance/man2docbook.bash $< 48 | 49 | disnixos-deploy-network.1: disnixos-deploy-network.in 50 | $(HELP2MAN) --output=$@ --no-info --name 'Installs or updates the infrastructure of a distributed system' "$(SHELL) disnixos-deploy-network" 51 | 52 | disnixos-deploy-network.1.xml: disnixos-deploy-network.1 53 | $(SHELL) ../maintenance/man2docbook.bash $< 54 | 55 | disnixos-snapshot-network.1: disnixos-snapshot-network.in 56 | $(HELP2MAN) --output=$@ --no-info --name 'Snapshots the state of all mutable components belonging to the system configurations' "$(SHELL) disnixos-snapshot-network" 57 | 58 | disnixos-snapshot-network.1.xml: disnixos-snapshot-network.1 59 | $(SHELL) ../maintenance/man2docbook.bash $< 60 | 61 | disnixos-restore-network.1: disnixos-restore-network.in 62 | $(HELP2MAN) --output=$@ --no-info --name 'Restores the state of all mutable components belonging to the system configurations' "$(SHELL) disnixos-restore-network" 63 | 64 | disnixos-restore-network.1.xml: disnixos-restore-network.1 65 | $(SHELL) ../maintenance/man2docbook.bash $< 66 | 67 | disnixos-collect-garbage.1: disnixos-collect-garbage.in 68 | $(HELP2MAN) --output=$@ --no-info --name 'Delete garbage from a network of machines' "$(SHELL) disnixos-collect-garbage" 69 | 70 | disnixos-collect-garbage.1.xml: disnixos-collect-garbage.1 71 | $(SHELL) ../maintenance/man2docbook.bash $< 72 | 73 | disnixos-clean-snapshots.1: disnixos-clean-snapshots.in 74 | $(HELP2MAN) --output=$@ --no-info --name 'Delete older generation of snapshots from a network of machines' "$(SHELL) disnixos-clean-snapshots" 75 | 76 | disnixos-clean-snapshots.1.xml: disnixos-clean-snapshots.1 77 | $(SHELL) ../maintenance/man2docbook.bash $< 78 | 79 | disnixos-delete-network-state.1: disnixos-delete-network-state.in 80 | $(HELP2MAN) --output=$@ --no-info --name 'Deletes the obsolete state of mutable components that have been undeployed' "$(SHELL) disnixos-delete-network-state" 81 | 82 | disnixos-delete-network-state.1.xml: disnixos-delete-network-state.1 83 | $(SHELL) ../maintenance/man2docbook.bash $< 84 | 85 | disnixos-query.1: disnixos-query.in 86 | $(HELP2MAN) --output=$@ --no-info --name 'Query the installed services from machines' "$(SHELL) disnixos-query" 87 | 88 | disnixos-query.1.xml: disnixos-query.1 89 | $(SHELL) ../maintenance/man2docbook.bash $< 90 | 91 | disnixos-vm-env.1: disnixos-vm-env.in 92 | $(HELP2MAN) --output=$@ --no-info --name 'Deploys and runs a distributed system in a network of VMs spawned by the NixOS test driver' "$(SHELL) disnixos-vm-env" 93 | 94 | disnixos-vm-env.1.xml: disnixos-vm-env.1 95 | $(SHELL) ../maintenance/man2docbook.bash $< 96 | 97 | disnixos-capture-manifest.1: disnixos-capture-manifest.in 98 | $(HELP2MAN) --output=$@ --no-info --name 'Captures all the ingredients for reconstructing a deployment manifest from the manifests of the target profiles' --libtool "$(SHELL) disnixos-capture-manifest" 99 | 100 | disnixos-capture-manifest.1.xml: disnixos-capture-manifest.1 101 | $(SHELL) ../maintenance/man2docbook.bash $< 102 | 103 | disnixos-reconstruct.1: disnixos-reconstruct.in 104 | $(HELP2MAN) --output=$@ --no-info --name 'Reconstructs the deployment manifest on the coordinator machine from the manifests on the target machines' --libtool "$(SHELL) disnixos-reconstruct" 105 | 106 | disnixos-reconstruct.1.xml: disnixos-reconstruct.1 107 | $(SHELL) ../maintenance/man2docbook.bash $< 108 | 109 | disnixos-convert-manifest.1: disnixos-convert-manifest.in 110 | $(HELP2MAN) --output=$@ --no-info --name 'Converts a manifest file using the old V1 schema into V2 format' --libtool "$(SHELL) disnixos-convert-manifest" 111 | 112 | disnixos-convert-manifest.1.xml: disnixos-convert-manifest.1 113 | $(SHELL) ../maintenance/man2docbook.bash $< 114 | 115 | disnixos-convert.1: disnixos-convert.in 116 | $(HELP2MAN) --output=$@ --no-info --name 'Converts a deployment using V1 manifests to V2' --libtool "$(SHELL) disnixos-convert" 117 | 118 | disnixos-convert.1.xml: disnixos-convert.1 119 | $(SHELL) ../maintenance/man2docbook.bash $< 120 | 121 | bin_SCRIPTS = disnix-backdoor-client disnix-nixops-client disnixos-geninfra \ 122 | disnixos-gentests disnixos-instantiate disnixos-manifest disnixos-delegate \ 123 | disnixos-env disnixos-vm-env disnixos-deploy-network disnixos-collect-garbage \ 124 | disnixos-clean-snapshots disnixos-query disnixos-snapshot-network \ 125 | disnixos-restore-network disnixos-delete-network-state \ 126 | disnixos-capture-manifest disnixos-reconstruct disnixos-convert-manifest \ 127 | disnixos-convert 128 | pkgdata_SCRIPTS = checks 129 | noinst_DATA = disnix-backdoor-client.1.xml disnix-nixops-client.1.xml \ 130 | disnixos-geninfra.1.xml disnixos-gentests.1.xml disnixos-instantiate.1.xml \ 131 | disnixos-manifest.1.xml disnixos-delegate.1.xml disnixos-env.1.xml \ 132 | disnixos-deploy-network.1.xml disnixos-collect-garbage.1.xml \ 133 | disnixos-clean-snapshots.1.xml disnixos-query.1.xml disnixos-vm-env.1.xml \ 134 | disnixos-capture-manifest.1.xml disnixos-reconstruct.1.xml \ 135 | disnixos-delete-network-state.1.xml disnixos-snapshot-network.1.xml \ 136 | disnixos-restore-network.1.xml disnixos-convert-manifest.1.xml \ 137 | disnixos-convert.1.xml 138 | man1_MANS = disnix-backdoor-client.1 disnix-nixops-client.1 disnixos-geninfra.1 \ 139 | disnixos-gentests.1 disnixos-instantiate.1 disnixos-manifest.1 \ 140 | disnixos-delegate.1 disnixos-env.1 disnixos-deploy-network.1 \ 141 | disnixos-collect-garbage.1 disnixos-clean-snapshots.1 disnixos-query.1 \ 142 | disnixos-vm-env.1 disnixos-snapshot-network.1 disnixos-restore-network.1 \ 143 | disnixos-delete-network-state.1 disnixos-capture-manifest.1 \ 144 | disnixos-reconstruct.1 disnixos-convert-manifest.1 disnixos-convert.1 145 | 146 | EXTRA_DIST = disnix-backdoor-client.in disnix-nixops-client.in \ 147 | disnixos-geninfra.in disnixos-gentests.in disnixos-instantiate.in \ 148 | disnixos-manifest.in disnixos-delegate.in disnixos-env.in disnixos-vm-env.in \ 149 | disnixos-deploy-network.in disnixos-collect-garbage.in \ 150 | disnixos-clean-snapshots.in disnixos-query.in disnixos-convert-manifest.in \ 151 | disnixos-convert.in \ 152 | $(pkgdata_SCRIPTS) \ 153 | $(man1_MANS) \ 154 | $(noinst_DATA) 155 | -------------------------------------------------------------------------------- /scripts/checks: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Checks whether a network expression is given. Exits with status 1 if not set. 23 | 24 | checkNetworkFiles() 25 | { 26 | if [ "$networkFiles" = "" ] 27 | then 28 | echo "ERROR: At least one network expression must be specified!" >&2 29 | exit 1 30 | fi 31 | } 32 | 33 | # Checks whether NixOps integration should be enabled 34 | 35 | checkUseNixOps() 36 | { 37 | if [ "$DISNIXOS_USE_NIXOPS" = "1" ] 38 | then 39 | useNixOps=1 40 | fi 41 | } 42 | 43 | # Sets all relevant parameter such as interface and nixOpsArgs to allow the 44 | # NixOps integration to work 45 | 46 | setNixOpsParams() 47 | { 48 | if [ "$useNixOps" = "1" ] 49 | then 50 | interface=disnix-nixops-client 51 | nixOpsArg="--use-nixops" 52 | fi 53 | } 54 | 55 | # Check all the possible input model combinations. Exists with status 1 if an 56 | # invalid combination is given or when a mandatory model is not specified. 57 | # When the right combination of input models is provided, it sets the modelArgs 58 | # environment variable with parameters that can be propagated to disnix-env or 59 | # disnix-manifest 60 | 61 | generateDisnixOSModelArgs() 62 | { 63 | if [ "$servicesFile" != "" ] || [ "$distributionFile" != "" ] 64 | then 65 | checkServicesFile 66 | checkDistributionFile 67 | 68 | modelArgs="-s $servicesFile -d $distributionFile" 69 | fi 70 | 71 | if [ "$packagesFile" != "" ] 72 | then 73 | checkPackagesFile 74 | modelArgs="$modelArgs -P $packagesFile" 75 | fi 76 | 77 | if [ "$modelArgs" = "" ] && [ "$undeploy" != "1" ] 78 | then 79 | echo "An unknown combination of inputs models were provided!" >&2 80 | exit 1 81 | fi 82 | 83 | checkNetworkFiles 84 | } 85 | -------------------------------------------------------------------------------- /scripts/disnixos-capture-manifest.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 142 | exit 1 143 | else 144 | while [ "$1" != "" ] 145 | do 146 | networkFiles="$networkFiles $(readlink -f $1)" 147 | shift 148 | done 149 | fi 150 | 151 | # Generate infrastructure model from network model 152 | infrastructureFile=`disnixos-geninfra --no-out-link $nixOpsArg $networkFiles` 153 | 154 | # Execute operation 155 | disnix-capture-manifest $profileArg $targetPropertyArg $maxConcurrentTransfersArg --interface $interface $infrastructureFile 156 | -------------------------------------------------------------------------------- /scripts/disnixos-clean-snapshots.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 147 | exit 1 148 | else 149 | while [ "$1" != "" ] 150 | do 151 | networkFiles="$networkFiles $(readlink -f $1)" 152 | shift 153 | done 154 | fi 155 | 156 | # Generate infrastructure model from network model 157 | infrastructureFile=`disnixos-geninfra --no-out-link $nixOpsArg $networkFiles` 158 | 159 | # Execute operation 160 | disnix-clean-snapshots $targetPropertyArg --interface $interface $keepArg $containerArg $componentArg $infrastructureFile 161 | -------------------------------------------------------------------------------- /scripts/disnixos-collect-garbage.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 135 | exit 1 136 | else 137 | while [ "$1" != "" ] 138 | do 139 | networkFiles="$networkFiles $(readlink -f $1)" 140 | shift 141 | done 142 | fi 143 | 144 | # Generate infrastructure model from network model 145 | infrastructureFile=`disnixos-geninfra --no-out-link $nixOpsArg $networkFiles` 146 | 147 | # Execute operation 148 | disnix-collect-garbage $deleteOldArg $targetPropertyArg --interface $interface $infrastructureFile 149 | -------------------------------------------------------------------------------- /scripts/disnixos-convert-manifest.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 145 | exit 1 146 | else 147 | while [ "$1" != "" ] 148 | do 149 | networkFileArgs="$networkFileArgs -n $(readlink -f $1)" 150 | shift 151 | done 152 | fi 153 | 154 | # Create a manifest file 155 | manifest=`disnixos-manifest $networkFileArgs --target-property $targetProperty --interface $interface --no-out-link $maxConcurrentTransfersArg $disableDisnixArg $showTraceArg` 156 | 157 | # Snapshot the state of the system derivations 158 | disnix-delete-state $profileArg $manifest 159 | -------------------------------------------------------------------------------- /scripts/disnixos-deploy-network.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 146 | exit 1 147 | else 148 | while [ "$1" != "" ] 149 | do 150 | networkFileArgs="$networkFileArgs -n $(readlink -f $1)" 151 | shift 152 | done 153 | fi 154 | 155 | if [ "$buildOnTargets" = "1" ] 156 | then 157 | # Build the components on the target machines if requested 158 | disnixos-delegate --target-property $targetProperty --interface $interface $maxConcurrentTransfersArg $disableDisnixArg $showTraceArg $networkFileArgs 159 | fi 160 | 161 | # Create a manifest file 162 | manifest=`disnixos-manifest $networkFileArgs --target-property $targetProperty --interface $interface --no-out-link $disableDisnixArg $showTraceArg` 163 | 164 | # Distribute system derivations 165 | disnix-distribute $maxConcurrentTransfersArg $manifest 166 | 167 | # Activate system derivations 168 | disnix-activate $profileArg --no-upgrade $manifest 169 | -------------------------------------------------------------------------------- /scripts/disnixos-geninfra.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 152 | exit 1 153 | else 154 | while [ "$1" != "" ] 155 | do 156 | networkFiles="$networkFiles $(readlink -f $1)" 157 | shift 158 | done 159 | fi 160 | 161 | # Execute operation 162 | nix-build @datadir@/@PACKAGE@/generate-infrastructure.nix --arg networkFiles "[ $networkFiles ]" $useBackdoorArg $useVMTesting $dysnomiaArg $nixOpsArg $showTraceArg $noOutLinkArg 163 | -------------------------------------------------------------------------------- /scripts/disnixos-gentests.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 132 | exit 1 133 | else 134 | manifestFile=$(readlink -f $@) 135 | fi 136 | 137 | # Execute operation 138 | nix-build @datadir@/@PACKAGE@/generate-tests.nix --argstr manifestFile $manifestFile --arg networkFiles "[ $networkFiles ]" $nixOpsArg $showTraceArg $noOutLinkArg 139 | -------------------------------------------------------------------------------- /scripts/disnixos-instantiate.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 139 | exit 1 140 | else 141 | while [ "$1" != "" ] 142 | do 143 | networkFiles="$networkFiles $(readlink -f $1)" 144 | shift 145 | done 146 | fi 147 | 148 | # Generate infrastructure model from network model 149 | infrastructureFile=`disnixos-geninfra --no-out-link $nixOpsArg $networkFiles` 150 | 151 | # Execute operation 152 | disnix-query $profileArg $targetPropertyArg $formatArg --interface $interface $infrastructureFile 153 | -------------------------------------------------------------------------------- /scripts/disnixos-reconstruct.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 162 | exit 1 163 | else 164 | while [ "$1" != "" ] 165 | do 166 | networkFiles="$networkFiles $(readlink -f $1)" 167 | shift 168 | done 169 | fi 170 | 171 | # Generate infrastructure model from network model 172 | infrastructureFile=`disnixos-geninfra --no-out-link $nixOpsArg $networkFiles` 173 | 174 | # Execute operation 175 | disnix-reconstruct $profileArg $targetPropertyArg $maxConcurrentTransfersArg $coordinatorProfilePathArg $noCoordinatorProfileArg $deployStateArg $showTraceArg --interface $interface $infrastructureFile 176 | -------------------------------------------------------------------------------- /scripts/disnixos-restore-network.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 151 | exit 1 152 | else 153 | while [ "$1" != "" ] 154 | do 155 | networkFileArgs="$networkFileArgs -n $(readlink -f $1)" 156 | shift 157 | done 158 | fi 159 | 160 | # Create a manifest file 161 | manifest=`disnixos-manifest $networkFileArgs --target-property $targetProperty --interface $interface --no-out-link $maxConcurrentTransfersArg $disableDisnixArg $showTraceArg` 162 | 163 | # Snapshot the state of the system derivations 164 | disnix-restore --no-upgrade $allArg $transferOnlyArg $profileArg $manifest 165 | -------------------------------------------------------------------------------- /scripts/disnixos-snapshot-network.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat <&2 151 | exit 1 152 | else 153 | while [ "$1" != "" ] 154 | do 155 | networkFileArgs="$networkFileArgs -n $(readlink -f $1)" 156 | shift 157 | done 158 | fi 159 | 160 | # Create a manifest file 161 | manifest=`disnixos-manifest $networkFileArgs --target-property $targetProperty --interface $interface --no-out-link $maxConcurrentTransfersArg $disableDisnixArg $showTraceArg` 162 | 163 | # Snapshot the state of the system derivations 164 | disnix-snapshot --no-upgrade $allArg $transferOnlyArg $profileArg $manifest 165 | -------------------------------------------------------------------------------- /scripts/disnixos-vm-env.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | set -o pipefail 4 | 5 | # DisnixOS - Infrastructure deployment extension for Disnix 6 | # Copyright (C) 2008-2022 Sander van der Burg 7 | # 8 | # This library is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public 10 | # License as published by the Free Software Foundation; either 11 | # version 2.1 of the License, or (at your option) any later version. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library; if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | # Shows the usage of this command to the user 23 | 24 | showUsage() 25 | { 26 | me="$(basename "$0")" 27 | 28 | cat < query.xml" 70 | ) 71 | 72 | coordinator.succeed( 73 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget1']/profileManifest/services/service[name='testService1']/name\" query.xml" 74 | ) 75 | coordinator.succeed( 76 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/service[name='testService2']/name\" query.xml" 77 | ) 78 | coordinator.succeed( 79 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/service[name='testService3']/name\" query.xml" 80 | ) 81 | ''; 82 | } 83 | -------------------------------------------------------------------------------- /tests/deployment-services-with-data.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, writeTextFile, openssh, dysnomia, disnix, disnixos}: 2 | 3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; }; 4 | 5 | let 6 | machine = import ./machine.nix { inherit dysnomia disnix disnixos; }; 7 | snapshotsTests = ./snapshots; 8 | 9 | physicalNetworkNix = import ./generate-physical-network.nix { inherit writeTextFile nixpkgs; }; 10 | 11 | env = "DYSNOMIA_STATEDIR=/root/dysnomia NIX_PATH=nixpkgs=${nixpkgs} SSH_OPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'"; 12 | in 13 | simpleTest { 14 | name = "deployment-services-with-data"; 15 | nodes = { 16 | coordinator = machine; 17 | testtarget1 = machine; 18 | testtarget2 = machine; 19 | }; 20 | testScript = 21 | '' 22 | import subprocess 23 | 24 | start_all() 25 | testtarget1.wait_for_unit("disnix") 26 | testtarget2.wait_for_unit("disnix") 27 | 28 | # Initialise ssh stuff by creating a key pair for communication 29 | key = subprocess.check_output( 30 | '${pkgs.openssh}/bin/ssh-keygen -t ecdsa -f key -N ""', 31 | shell=True, 32 | ) 33 | 34 | testtarget1.succeed("mkdir -m 700 /root/.ssh") 35 | testtarget1.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 36 | 37 | testtarget2.succeed("mkdir -m 700 /root/.ssh") 38 | testtarget2.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 39 | 40 | coordinator.succeed("mkdir -m 700 /root/.ssh") 41 | coordinator.copy_from_host("key", "/root/.ssh/id_dsa") 42 | coordinator.succeed("chmod 600 /root/.ssh/id_dsa") 43 | 44 | # Deploy a NixOS network and services including state 45 | coordinator.succeed( 46 | "${env} dysnomia=\"$(dirname $(readlink -f $(type -p dysnomia)))/..\" disnixos-env -s ${snapshotsTests}/services-state.nix -n ${physicalNetworkNix} -d ${snapshotsTests}/distribution-simple.nix --disable-disnix --no-infra-deployment" 47 | ) 48 | 49 | # Check if the state is actually deployed 50 | result = testtarget1.succeed("cat /var/db/testService1/state") 51 | 52 | if result[:-1] == "0": 53 | print("result is: 0") 54 | else: 55 | raise Exception("result should be: 0, but it is: {}".format(result)) 56 | 57 | result = testtarget2.succeed("cat /var/db/testService2/state") 58 | 59 | if result[:-1] == "0": 60 | print("result is: 0") 61 | else: 62 | raise Exception("result should be: 0, but it is: {}".format(result)) 63 | 64 | # Modify the state 65 | 66 | testtarget1.succeed("echo 1 > /var/db/testService1/state") 67 | testtarget2.succeed("echo 2 > /var/db/testService2/state") 68 | 69 | # Redeploy the services by reversing their distribution 70 | coordinator.succeed( 71 | "${env} dysnomia=\"$(dirname $(readlink -f $(type -p dysnomia)))/..\" disnixos-env -s ${snapshotsTests}/services-state.nix -n ${physicalNetworkNix} -d ${snapshotsTests}/distribution-reverse.nix --disable-disnix --no-infra-deployment" 72 | ) 73 | 74 | # Check if the state has been migrated correctly 75 | result = testtarget1.succeed("cat /var/db/testService2/state") 76 | 77 | if result[:-1] == "2": 78 | print("result is: 2") 79 | else: 80 | raise Exception("result should be: 2") 81 | 82 | result = testtarget2.succeed("cat /var/db/testService1/state") 83 | 84 | if result[:-1] == "1": 85 | print("result is: 1") 86 | else: 87 | raise Exception("result should be: 1") 88 | 89 | # Run the clean snapshots operation to wipe out all snapshots on the target 90 | # machines and check if they are really removed. 91 | 92 | coordinator.succeed( 93 | "${env} disnixos-clean-snapshots --keep 0 ${physicalNetworkNix}" 94 | ) 95 | 96 | result = testtarget1.succeed( 97 | "dysnomia-snapshots --query-all --container wrapper --component testService1 | wc -l" 98 | ) 99 | 100 | if int(result) == 0: 101 | print("result is: 0") 102 | else: 103 | raise Exception("result should be: 0, but it is: {}".format(result)) 104 | 105 | result = testtarget2.succeed( 106 | "dysnomia-snapshots --query-all --container wrapper --component testService2 | wc -l" 107 | ) 108 | 109 | if int(result) == 0: 110 | print("result is: 0") 111 | else: 112 | raise Exception("result should be: 0, but it is: {}".format(result)) 113 | ''; 114 | } 115 | -------------------------------------------------------------------------------- /tests/deployment-services.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, writeTextFile, openssh, dysnomia, disnix, disnixos}: 2 | 3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; }; 4 | 5 | let 6 | machine = import ./machine.nix { inherit dysnomia disnix disnixos; }; 7 | manifestTests = ./manifest; 8 | 9 | physicalNetworkNix = import ./generate-physical-network.nix { inherit writeTextFile nixpkgs; }; 10 | 11 | env = "NIX_PATH=nixpkgs=${nixpkgs} SSH_OPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'"; 12 | in 13 | simpleTest { 14 | name = "deployment-services"; 15 | nodes = { 16 | coordinator = machine; 17 | testtarget1 = machine; 18 | testtarget2 = machine; 19 | }; 20 | testScript = 21 | '' 22 | import subprocess 23 | 24 | start_all() 25 | 26 | testtarget1.wait_for_unit("disnix") 27 | testtarget2.wait_for_unit("disnix") 28 | 29 | # Initialise ssh stuff by creating a key pair for communication 30 | key = subprocess.check_output( 31 | '${pkgs.openssh}/bin/ssh-keygen -t ecdsa -f key -N ""', 32 | shell=True, 33 | ) 34 | 35 | testtarget1.succeed("mkdir -m 700 /root/.ssh") 36 | testtarget1.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 37 | 38 | testtarget2.succeed("mkdir -m 700 /root/.ssh") 39 | testtarget2.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 40 | 41 | coordinator.succeed("mkdir -m 700 /root/.ssh") 42 | coordinator.copy_from_host("key", "/root/.ssh/id_dsa") 43 | coordinator.succeed("chmod 600 /root/.ssh/id_dsa") 44 | 45 | # Deploy a packages configuration and check whether they have been successfully installed 46 | coordinator.succeed( 47 | "${env} disnixos-env -P ${manifestTests}/target-pkgs.nix -n ${physicalNetworkNix} --disable-disnix --no-infra-deployment" 48 | ) 49 | testtarget1.succeed("/nix/var/nix/profiles/disnix/default/bin/curl --version") 50 | testtarget2.succeed("/nix/var/nix/profiles/disnix/default/bin/strace -h") 51 | 52 | # Deploy a NixOS network and services in a network specified by a NixOS network expression simultaneously 53 | coordinator.succeed( 54 | "${env} disnixos-env -s ${manifestTests}/services.nix -n ${physicalNetworkNix} -d ${manifestTests}/distribution.nix --disable-disnix --no-infra-deployment" 55 | ) 56 | 57 | # Use disnixos-query to see if the right services are installed on 58 | # the right target platforms. This test should succeed. 59 | coordinator.succeed( 60 | "${env} disnixos-query -f xml ${physicalNetworkNix} > query.xml" 61 | ) 62 | 63 | coordinator.succeed( 64 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget1']/profileManifest/services/service[name='testService1']/name\" query.xml" 65 | ) 66 | coordinator.succeed( 67 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/service[name='testService2']/name\" query.xml" 68 | ) 69 | coordinator.succeed( 70 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/service[name='testService3']/name\" query.xml" 71 | ) 72 | 73 | # Undeploy the entire system and check if no services are on the target machines 74 | coordinator.succeed( 75 | "${env} disnixos-env --undeploy -n ${physicalNetworkNix} --disable-disnix --no-infra-deployment" 76 | ) 77 | coordinator.succeed( 78 | "${env} disnixos-query -f xml ${physicalNetworkNix} > query.xml" 79 | ) 80 | 81 | coordinator.fail( 82 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget1']/profileManifest/services/*\" query.xml" 83 | ) 84 | coordinator.fail( 85 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/*\" query.xml" 86 | ) 87 | ''; 88 | } 89 | -------------------------------------------------------------------------------- /tests/distbuild-infra.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, writeTextFile, openssh, dysnomia, disnix, disnixos}: 2 | 3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; }; 4 | 5 | let 6 | machine = import ./machine.nix { inherit dysnomia disnix disnixos; }; 7 | 8 | logicalNetworkNix = import ./generate-logical-network.nix { inherit writeTextFile; }; 9 | physicalNetworkNix = import ./generate-physical-network.nix { inherit nixpkgs writeTextFile; }; 10 | in 11 | simpleTest { 12 | name = "distbuild-infra"; 13 | nodes = { 14 | coordinator = machine; 15 | testtarget1 = machine; 16 | testtarget2 = machine; 17 | }; 18 | testScript = 19 | '' 20 | import subprocess 21 | 22 | start_all() 23 | 24 | coordinator.wait_for_unit("network-interfaces.target") 25 | testtarget1.wait_for_unit("disnix") 26 | testtarget2.wait_for_unit("disnix") 27 | 28 | # Initialise ssh stuff by creating a key pair for communication 29 | key = subprocess.check_output( 30 | '${pkgs.openssh}/bin/ssh-keygen -t ecdsa -f key -N ""', 31 | shell=True, 32 | ) 33 | 34 | testtarget1.succeed("mkdir -m 700 /root/.ssh") 35 | testtarget1.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 36 | 37 | testtarget2.succeed("mkdir -m 700 /root/.ssh") 38 | testtarget2.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 39 | 40 | coordinator.succeed("mkdir -m 700 /root/.ssh") 41 | coordinator.copy_from_host("key", "/root/.ssh/id_dsa") 42 | coordinator.succeed("chmod 600 /root/.ssh/id_dsa") 43 | 44 | # Deploy the test NixOS network expression. This test should succeed. 45 | coordinator.succeed( 46 | "NIX_PATH=nixpkgs=${nixpkgs} SSH_OPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no' disnixos-deploy-network ${logicalNetworkNix} ${physicalNetworkNix} --disable-disnix --build-on-targets" 47 | ) 48 | 49 | # Check if zip is installed on the correct machine 50 | testtarget1.succeed("zip -h") 51 | testtarget2.fail("zip -h") 52 | 53 | # Check if hello is installed on the correct machine 54 | testtarget2.succeed("hello") 55 | testtarget1.fail("hello") 56 | ''; 57 | } 58 | -------------------------------------------------------------------------------- /tests/distbuild-services.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, writeTextFile, openssh, dysnomia, disnix, disnixos}: 2 | 3 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; }; 4 | 5 | let 6 | machine = import ./machine.nix { inherit dysnomia disnix disnixos; }; 7 | manifestTests = ./manifest; 8 | 9 | physicalNetworkNix = import ./generate-physical-network.nix { inherit writeTextFile nixpkgs; }; 10 | 11 | env = "NIX_PATH=nixpkgs=${nixpkgs} SSH_OPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'"; 12 | in 13 | simpleTest { 14 | name = "distbuild-services"; 15 | nodes = { 16 | coordinator = machine; 17 | testtarget1 = machine; 18 | testtarget2 = machine; 19 | }; 20 | testScript = 21 | '' 22 | import subprocess 23 | 24 | start_all() 25 | 26 | coordinator.wait_for_unit("network-interfaces.target") 27 | testtarget1.wait_for_unit("disnix") 28 | testtarget2.wait_for_unit("disnix") 29 | 30 | # Initialise ssh stuff by creating a key pair for communication 31 | key = subprocess.check_output( 32 | '${pkgs.openssh}/bin/ssh-keygen -t ecdsa -f key -N ""', 33 | shell=True, 34 | ) 35 | 36 | testtarget1.succeed("mkdir -m 700 /root/.ssh") 37 | testtarget1.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 38 | 39 | testtarget2.succeed("mkdir -m 700 /root/.ssh") 40 | testtarget2.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 41 | 42 | coordinator.succeed("mkdir -m 700 /root/.ssh") 43 | coordinator.copy_from_host("key", "/root/.ssh/id_dsa") 44 | coordinator.succeed("chmod 600 /root/.ssh/id_dsa") 45 | 46 | # Deploy a NixOS network and services in a network specified by a NixOS network expression simultaneously 47 | coordinator.succeed( 48 | "${env} disnixos-env -s ${manifestTests}/services.nix -n ${physicalNetworkNix} -d ${manifestTests}/distribution.nix --disable-disnix --no-infra-deployment --build-on-targets" 49 | ) 50 | 51 | # Use disnixos-query to see if the right services are installed on 52 | # the right target platforms. This test should succeed. 53 | coordinator.succeed( 54 | "${env} disnixos-query -f xml ${physicalNetworkNix} > query.xml" 55 | ) 56 | coordinator.succeed( 57 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget1']/profileManifest/services/service[name='testService1']/name\" query.xml" 58 | ) 59 | coordinator.succeed( 60 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/service[name='testService2']/name\" query.xml" 61 | ) 62 | coordinator.succeed( 63 | "xmllint --xpath \"/profileManifestTargets/target[@name='testtarget2']/profileManifest/services/service[name='testService3']/name\" query.xml" 64 | ) 65 | ''; 66 | } 67 | -------------------------------------------------------------------------------- /tests/generate-logical-config.nix: -------------------------------------------------------------------------------- 1 | {writeTextFile}: 2 | 3 | writeTextFile { 4 | name = "network-logical.nix"; 5 | text = '' 6 | { 7 | server = {pkgs, ...}: 8 | 9 | { 10 | environment.systemPackages = [ pkgs.zip ]; 11 | 12 | environment.etc."dysnomia/properties" = { 13 | source = pkgs.writeTextFile { 14 | name = "dysnomia-properties"; 15 | text = ''' 16 | foo=bar 17 | supportedTypes=("process" "wrapper") 18 | '''; 19 | }; 20 | }; 21 | }; 22 | } 23 | ''; 24 | } 25 | -------------------------------------------------------------------------------- /tests/generate-logical-network.nix: -------------------------------------------------------------------------------- 1 | {writeTextFile}: 2 | 3 | writeTextFile { 4 | name = "network-logical.nix"; 5 | 6 | text = '' 7 | { 8 | testtarget1 = {pkgs, ...}: 9 | 10 | { 11 | environment.systemPackages = [ pkgs.zip ]; 12 | }; 13 | 14 | testtarget2 = {pkgs, ...}: 15 | 16 | { 17 | environment.systemPackages = [ pkgs.hello ]; 18 | }; 19 | } 20 | ''; 21 | } 22 | -------------------------------------------------------------------------------- /tests/generate-physical-config.nix: -------------------------------------------------------------------------------- 1 | {writeTextFile, nixpkgs, dysnomia, disnix}: 2 | 3 | writeTextFile { 4 | name = "network-physical.nix"; 5 | 6 | text = '' 7 | { 8 | server = {pkgs, ...}: 9 | 10 | { 11 | require = [ 12 | "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" 13 | "${nixpkgs}/nixos/modules/testing/test-instrumentation.nix" 14 | ]; 15 | boot.loader.grub.enable = false; 16 | documentation.nixos.enable = false; 17 | services.dbus.enable = true; 18 | services.openssh.enable = true; 19 | networking.firewall.enable = false; 20 | 21 | # Ugly: Replicates assignIPAddresses from build-vms.nix. 22 | networking.interfaces.eth1.ipv4.addresses = [ { 23 | address = "192.168.1.2"; 24 | prefixLength = 24; 25 | } ]; 26 | 27 | # Create dummy Disnix job that does nothing. This prevents it from stopping. 28 | systemd.services.disnix = 29 | { description = "Disnix dummy server"; 30 | 31 | wantedBy = [ "multi-user.target" ]; 32 | restartIfChanged = false; 33 | script = "true"; 34 | }; 35 | 36 | environment.systemPackages = [ "${disnix}" "${dysnomia}" ]; 37 | 38 | deployment.targetEnv = "none"; 39 | }; 40 | } 41 | ''; 42 | } 43 | -------------------------------------------------------------------------------- /tests/generate-physical-network-for-nixops.nix: -------------------------------------------------------------------------------- 1 | {writeTextFile, nixpkgs, disnix}: 2 | 3 | writeTextFile { 4 | name = "network-physical.nix"; 5 | 6 | text = '' 7 | let 8 | machine = {hostname}: {pkgs, ...}: 9 | 10 | { 11 | require = [ 12 | "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" 13 | "${nixpkgs}/nixos/modules/testing/test-instrumentation.nix" 14 | ]; 15 | boot.loader.grub.enable = false; 16 | documentation.nixos.enable = false; 17 | services.dbus.enable = true; 18 | services.openssh.enable = true; 19 | networking.firewall.enable = false; 20 | 21 | # Ugly: Replicates assignIPAddresses from build-vms.nix. 22 | networking.interfaces.eth1.ipv4.addresses = [ { 23 | address = if hostname == "testtarget1" then "192.168.1.2" 24 | else if hostname == "testtarget2" then "192.168.1.3" 25 | else throw "Unknown hostname: "+hostname; 26 | prefixLength = 24; 27 | } ]; 28 | 29 | # Create dummy Disnix job that does nothing. This prevents it from stopping. 30 | systemd.services.disnix = 31 | { description = "Disnix dummy server"; 32 | 33 | wantedBy = [ "multi-user.target" ]; 34 | restartIfChanged = false; 35 | script = "true"; 36 | }; 37 | 38 | environment.systemPackages = [ "${disnix}" ]; 39 | 40 | deployment.targetEnv = "none"; 41 | }; 42 | in 43 | { 44 | testtarget1 = machine { hostname = "testtarget1"; }; 45 | testtarget2 = machine { hostname = "testtarget2"; }; 46 | } 47 | ''; 48 | } 49 | -------------------------------------------------------------------------------- /tests/generate-physical-network.nix: -------------------------------------------------------------------------------- 1 | {writeTextFile, nixpkgs}: 2 | 3 | writeTextFile { 4 | name = "network-physical.nix"; 5 | 6 | text = '' 7 | let 8 | machine = {hostname}: {pkgs, ...}: 9 | 10 | { 11 | require = [ 12 | "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix" 13 | "${nixpkgs}/nixos/modules/testing/test-instrumentation.nix" 14 | ]; 15 | boot.loader.grub.enable = false; 16 | disnixInfrastructure.enable = true; 17 | disnixInfrastructure.infrastructure.hostname = hostname; 18 | documentation.nixos.enable = false; 19 | services.dbus.enable = true; 20 | services.openssh.enable = true; 21 | networking.firewall.enable = false; 22 | 23 | # Ugly: Replicates assignIPAddresses from build-vms.nix. 24 | networking.interfaces.eth1.ipv4.addresses = [ { 25 | address = if hostname == "testtarget1" then "192.168.1.2" 26 | else if hostname == "testtarget2" then "192.168.1.3" 27 | else throw "Unknown hostname: "+hostname; 28 | prefixLength = 24; 29 | } ]; 30 | 31 | # Create dummy Disnix job that does nothing. This prevents it from stopping. 32 | systemd.services.disnix = 33 | { description = "Disnix dummy server"; 34 | wantedBy = [ "multi-user.target" ]; 35 | restartIfChanged = false; 36 | script = "true"; 37 | }; 38 | }; 39 | in 40 | { 41 | testtarget1 = machine { hostname = "testtarget1"; }; 42 | testtarget2 = machine { hostname = "testtarget2"; }; 43 | } 44 | ''; 45 | } 46 | -------------------------------------------------------------------------------- /tests/machine-with-nixops.nix: -------------------------------------------------------------------------------- 1 | {dysnomia, disnix, disnixos}: 2 | {config, pkgs, ...}: 3 | 4 | { 5 | virtualisation = { 6 | writableStore = true; 7 | memorySize = 16384; 8 | diskSize = 10240; 9 | additionalPaths = [ pkgs.stdenv pkgs.stdenvNoCC ]; 10 | }; 11 | 12 | ids.gids = { disnix = 200; }; 13 | users.extraGroups = { 14 | disnix = { gid = 200; }; 15 | }; 16 | networking.firewall.enable = false; 17 | 18 | services.dbus.enable = true; 19 | services.dbus.packages = [ disnix ]; 20 | services.openssh.enable = true; 21 | 22 | #systemd.services.ssh.restartIfChanged = false; 23 | 24 | systemd.services.disnix = 25 | { description = "Disnix server"; 26 | 27 | wantedBy = [ "multi-user.target" ]; 28 | after = [ "dbus.service" ]; 29 | 30 | path = [ pkgs.nix disnix dysnomia ]; 31 | 32 | environment = { 33 | HOME = "/root"; 34 | }; 35 | 36 | serviceConfig.ExecStart = "${disnix}/bin/disnix-service"; 37 | }; 38 | 39 | # We can't download any substitutes in a test environment. To make tests 40 | # faster, we disable substitutes so that Nix does not waste any time by 41 | # attempting to download them. 42 | nix.extraOptions = '' 43 | substitute = false 44 | ''; 45 | 46 | nixpkgs.config.permittedInsecurePackages = [ 47 | "python-2.7.18.6" 48 | "python2.7-certifi-2021.10.8" 49 | "python2.7-pyjwt-1.7.1" 50 | "openssl-1.1.1v" 51 | ]; 52 | 53 | environment.systemPackages = [ pkgs.nix dysnomia disnix disnixos pkgs.hello pkgs.zip pkgs.nixops pkgs.libxml2 ]; 54 | environment.variables.DISNIX_REMOTE_CLIENT = "disnix-client"; 55 | 56 | system.extraDependencies = [ 57 | pkgs.stdenv 58 | pkgs.busybox 59 | pkgs.perlPackages.ArchiveCpio 60 | 61 | pkgs.util-linux 62 | pkgs.texinfo 63 | pkgs.xorg.lndir 64 | pkgs.getconf 65 | pkgs.desktop-file-utils 66 | ] 67 | ++ pkgs.coreutils.all 68 | ++ pkgs.libxml2.all 69 | ++ pkgs.libxslt.all; 70 | } 71 | -------------------------------------------------------------------------------- /tests/machine.nix: -------------------------------------------------------------------------------- 1 | {disnix, dysnomia, disnixos}: 2 | {config, pkgs, lib, ...}: 3 | 4 | { 5 | virtualisation = { 6 | writableStore = true; 7 | memorySize = 16384; 8 | diskSize = 40960; 9 | additionalPaths = [ pkgs.stdenv pkgs.stdenvNoCC ]; 10 | }; 11 | 12 | ids.gids = { disnix = 200; }; 13 | users.extraGroups = { 14 | disnix = { gid = 200; }; 15 | }; 16 | 17 | services.dbus.enable = true; 18 | services.dbus.packages = [ disnix ]; 19 | services.openssh.enable = true; 20 | 21 | systemd.services.ssh.restartIfChanged = false; 22 | 23 | systemd.services.disnix = 24 | { description = "Disnix server"; 25 | 26 | wantedBy = [ "multi-user.target" ]; 27 | after = [ "dbus.service" ]; 28 | 29 | path = [ pkgs.nix pkgs.getopt disnix dysnomia ]; 30 | environment = { 31 | HOME = "/root"; 32 | }; 33 | 34 | serviceConfig.ExecStart = "${disnix}/bin/disnix-service"; 35 | }; 36 | 37 | # We can't download any substitutes in a test environment. To make tests 38 | # faster, we disable substitutes so that Nix does not waste any time by 39 | # attempting to download them. 40 | nix.settings = { 41 | substituters = lib.mkForce []; 42 | hashed-mirrors = null; 43 | connect-timeout = 1; 44 | }; 45 | 46 | environment.systemPackages = [ pkgs.nix dysnomia disnix disnixos pkgs.hello pkgs.zip pkgs.libxml2 ]; 47 | environment.variables.DISNIX_REMOTE_CLIENT = "disnix-client"; 48 | 49 | # Add all dependencies that allow rebuilds and deploying NixOS without a network connection 50 | system.extraDependencies = [ 51 | pkgs.stdenv 52 | pkgs.busybox 53 | pkgs.perlPackages.ArchiveCpio 54 | pkgs.e2fsprogs 55 | 56 | pkgs.util-linux 57 | pkgs.texinfo 58 | pkgs.xorg.lndir 59 | pkgs.getconf 60 | pkgs.desktop-file-utils 61 | ] 62 | ++ pkgs.brotli.all 63 | ++ pkgs.kmod.all 64 | ++ pkgs.libarchive.all 65 | ++ pkgs.libxml2.all 66 | ++ pkgs.libxslt.all; 67 | 68 | system.includeBuildDependencies = true; 69 | } 70 | -------------------------------------------------------------------------------- /tests/manifest/distribution-server.nix: -------------------------------------------------------------------------------- 1 | {infrastructure}: 2 | 3 | { 4 | testService1 = [ infrastructure.server ]; 5 | testService2 = [ infrastructure.server ]; 6 | testService3 = [ infrastructure.server ]; 7 | } 8 | -------------------------------------------------------------------------------- /tests/manifest/distribution.nix: -------------------------------------------------------------------------------- 1 | {infrastructure}: 2 | 3 | { 4 | testService1 = [ infrastructure.testtarget1 ]; 5 | testService2 = [ infrastructure.testtarget2 ]; 6 | testService3 = [ infrastructure.testtarget2 ]; 7 | } 8 | -------------------------------------------------------------------------------- /tests/manifest/pkgs/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, system}: 2 | 3 | rec { 4 | testService1 = import ./testService1.nix { 5 | inherit (pkgs) stdenv; 6 | }; 7 | 8 | testService2 = import ./testService2.nix { 9 | inherit (pkgs) stdenv lib; 10 | }; 11 | 12 | testService3 = import ./testService3.nix { 13 | inherit (pkgs) stdenv lib; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /tests/manifest/pkgs/testService1.nix: -------------------------------------------------------------------------------- 1 | {stdenv}: 2 | 3 | stdenv.mkDerivation { 4 | name = "testService1"; 5 | 6 | buildCommand = '' 7 | mkdir -p $out 8 | echo "testService1" > $out/config 9 | ''; 10 | } 11 | -------------------------------------------------------------------------------- /tests/manifest/pkgs/testService2.nix: -------------------------------------------------------------------------------- 1 | {stdenv, lib}: 2 | {testService1}: 3 | 4 | stdenv.mkDerivation { 5 | name = "testService2"; 6 | buildCommand = '' 7 | mkdir -p $out 8 | 9 | ( 10 | echo "testService2" 11 | echo "Depends on service: ${testService1.name}" 12 | echo "Targets:" 13 | cat < $out/config 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /tests/manifest/pkgs/testService3.nix: -------------------------------------------------------------------------------- 1 | {stdenv, lib}: 2 | {testService1, testService2}: 3 | 4 | stdenv.mkDerivation { 5 | name = "testService3"; 6 | buildCommand = '' 7 | mkdir -p $out 8 | 9 | ( 10 | echo "testService3" 11 | echo "Depends on service: ${testService1.name}" 12 | echo "Targets:" 13 | cat < $out/config 25 | ''; 26 | } 27 | -------------------------------------------------------------------------------- /tests/manifest/services.nix: -------------------------------------------------------------------------------- 1 | {distribution, invDistribution, system, pkgs}: 2 | 3 | let 4 | customPkgs = import ./pkgs { inherit pkgs system; }; 5 | in 6 | rec { 7 | testService1 = { 8 | name = "testService1"; 9 | pkg = customPkgs.testService1; 10 | type = "echo"; 11 | }; 12 | 13 | testService2 = { 14 | name = "testService2"; 15 | pkg = customPkgs.testService2; 16 | dependsOn = { 17 | inherit testService1; 18 | }; 19 | type = "echo"; 20 | }; 21 | 22 | testService3 = { 23 | name = "testService3"; 24 | pkg = customPkgs.testService3; 25 | dependsOn = { 26 | inherit testService1 testService2; 27 | }; 28 | type = "echo"; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /tests/manifest/target-pkgs.nix: -------------------------------------------------------------------------------- 1 | {system, pkgs}: 2 | 3 | { 4 | testtarget1 = [ 5 | pkgs.curl 6 | ]; 7 | testtarget2 = [ 8 | pkgs.strace 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /tests/nixops-client.nix: -------------------------------------------------------------------------------- 1 | {nixpkgs, writeTextFile, openssh, dysnomia, disnix, disnixos, disnixRemoteClient}: 2 | 3 | let 4 | manifestTests = ./manifest; 5 | machine = import ./machine-with-nixops.nix { inherit dysnomia disnix disnixos; }; 6 | 7 | logicalNetworkNix = import ./generate-logical-config.nix { inherit writeTextFile; }; 8 | physicalNetworkNix = import ./generate-physical-config.nix { inherit writeTextFile nixpkgs dysnomia disnix; }; 9 | in 10 | with import "${nixpkgs}/nixos/lib/testing-python.nix" { system = builtins.currentSystem; }; 11 | 12 | simpleTest { 13 | name = "nixops-client"; 14 | nodes = { 15 | client = machine; 16 | server = machine; 17 | }; 18 | testScript = 19 | let 20 | env = "NIX_PATH='nixpkgs=${nixpkgs}:nixos=${nixpkgs}/nixos' DISNIX_REMOTE_CLIENT=${disnixRemoteClient}"; 21 | in 22 | '' 23 | import subprocess 24 | 25 | start_all() 26 | 27 | server.wait_for_unit("sshd") 28 | client.wait_for_unit("sshd") 29 | 30 | manifest = client.succeed( 31 | "${env} disnixos-manifest -s ${manifestTests}/services.nix -n ${logicalNetworkNix} -n ${physicalNetworkNix} -d ${manifestTests}/distribution-server.nix --use-nixops" 32 | ) 33 | closureList = client.succeed("nix-store -qR {}".format(manifest)).split("\n") 34 | 35 | # Initialise ssh stuff by creating a key pair for communication 36 | key = subprocess.check_output( 37 | '${pkgs.openssh}/bin/ssh-keygen -t ecdsa -f key -N ""', 38 | shell=True, 39 | ) 40 | 41 | server.succeed("mkdir -m 700 /root/.ssh") 42 | server.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 43 | 44 | client.succeed("mkdir -m 700 /root/.ssh") 45 | client.copy_from_host("key.pub", "/root/.ssh/authorized_keys") 46 | client.copy_from_host("key", "/root/.ssh/id_dsa") 47 | client.succeed("chmod 600 /root/.ssh/id_dsa") 48 | 49 | # Test SSH connectivity 50 | client.succeed("ssh -o StrictHostKeyChecking=no -v server ls /") 51 | 52 | # Deploy infrastructure with NixOps 53 | client.succeed( 54 | "nixops create ${logicalNetworkNix} ${physicalNetworkNix}" 55 | ) 56 | client.succeed( 57 | "${env} nixops deploy" 58 | ) 59 | 60 | #### Test disnix-nixops-client 61 | 62 | # Check invalid path. We query an invalid path from the service 63 | # which should return the path we have given. 64 | # This test should succeed. 65 | 66 | result = client.succeed( 67 | "${env} disnix-nixops-client --target server --print-invalid /nix/store/00000000000000000000000000000000-invalid" 68 | ) 69 | 70 | if "/nix/store/00000000000000000000000000000000-invalid" in result: 71 | print("/nix/store/00000000000000000000000000000000-invalid is invalid") 72 | else: 73 | raise Exception( 74 | "/nix/store/00000000000000000000000000000000-invalid should be invalid" 75 | ) 76 | 77 | # Check invalid path. We query a valid path from the service 78 | # which should return nothing in this case. 79 | # This test should succeed. 80 | 81 | result = client.succeed( 82 | "${env} disnix-nixops-client --target server --print-invalid ${pkgs.bash}" 83 | ) 84 | 85 | # Query requisites test. Queries the requisites of the bash shell 86 | # and checks whether it is part of the closure. 87 | # This test should succeed. 88 | 89 | result = client.succeed( 90 | "${env} disnix-nixops-client --target server --query-requisites ${pkgs.bash}" 91 | ) 92 | 93 | if "bash" in result: 94 | print("${pkgs.bash} is in the closure") 95 | else: 96 | raise Exception( 97 | "${pkgs.bash} should be in the closure!" 98 | ) 99 | 100 | # Realise test. First the coreutils derivation file is instantiated, 101 | # then it is realised. This test should succeed. 102 | 103 | result = server.succeed( 104 | "nix-instantiate ${nixpkgs} -A coreutils" 105 | ) 106 | client.succeed( 107 | "${env} disnix-nixops-client --target server --realise {}".format( 108 | result 109 | ) 110 | ) 111 | 112 | # Export test. Exports the closure of the bash shell on the server 113 | # and then imports it on the client. This test should succeed. 114 | 115 | result = client.succeed( 116 | "${env} disnix-nixops-client --target server --export --remotefile ${pkgs.bash}" 117 | ) 118 | client.succeed("nix-store --import < {}".format(result)) 119 | 120 | # Repeat the same export operation, but now as a localfile. It should 121 | # export the same closure to a file. This test should succeed. 122 | result = client.succeed( 123 | "${env} disnix-nixops-client --target server --export --localfile ${pkgs.bash}" 124 | ) 125 | server.succeed("[ -e {} ]".format(result)) 126 | 127 | # Import test. Creates a closure of the serverProfile on the 128 | # client. Then it imports the closure into the Nix store of the 129 | # server. This test should succeed. 130 | 131 | serverProfile = [c for c in closureList if "-server" in c][0] 132 | server.fail("nix-store --check-validity {}".format(serverProfile)) 133 | client.succeed( 134 | "nix-store --export $(nix-store -qR {}) > /root/serverProfile.closure".format( 135 | serverProfile 136 | ) 137 | ) 138 | client.succeed( 139 | "${env} disnix-nixops-client --target server --import --localfile /root/serverProfile.closure" 140 | ) 141 | server.succeed("nix-store --check-validity {}".format(serverProfile)) 142 | 143 | # Do a remotefile import. It should import the bash closure stored 144 | # remotely. This test should succeed. 145 | server.succeed("nix-store --export $(nix-store -qR /bin/sh) > /root/bash.closure") 146 | client.succeed( 147 | "${env} disnix-nixops-client --target server --import --remotefile /root/bash.closure" 148 | ) 149 | 150 | # Set test. Adds the server profile as only derivation into 151 | # the Disnix profile. We first set the profile, then we check 152 | # whether the profile is part of the closure. 153 | # This test should succeed. 154 | 155 | client.succeed( 156 | "${env} disnix-nixops-client --target server --set --profile default {}".format( 157 | serverProfile 158 | ) 159 | ) 160 | defaultProfileClosure = server.succeed( 161 | "nix-store -qR /nix/var/nix/profiles/disnix/default" 162 | ).split("\n") 163 | 164 | if serverProfile in defaultProfileClosure: 165 | print("{} is part of the closure".format(serverProfile)) 166 | else: 167 | raise Exception("{} should be part of the closure".format(serverProfile)) 168 | 169 | # Query installed test. Queries the installed services in the 170 | # profile, which has been set in the previous testcase. 171 | # testService2 should be in there. This test should succeed. 172 | 173 | closure = client.succeed( 174 | "${env} disnix-nixops-client --target server --query-installed --profile default" 175 | ) 176 | if "testService2" in closure: 177 | print("testService2 is installed in the default profile") 178 | else: 179 | raise Exception("testService2 should be installed in the default profile") 180 | 181 | # Collect garbage test. This test should succeed. 182 | # Testcase disabled, as this is very expensive. 183 | # client.succeed("${env} disnix-nixops-client --target server --collect-garbage") 184 | 185 | # Lock test. This test should succeed. 186 | client.succeed( 187 | "${env} disnix-nixops-client --target server --lock" 188 | ) 189 | 190 | # Lock test. This test should fail, since the service instance is already locked 191 | client.fail( 192 | "${env} disnix-nixops-client --target server --lock" 193 | ) 194 | 195 | # Unlock test. This test should succeed, so that we can release the lock 196 | client.succeed( 197 | "${env} disnix-nixops-client --target server --unlock" 198 | ) 199 | 200 | # Unlock test. This test should fail as the lock has already been released 201 | client.fail( 202 | "${env} disnix-nixops-client --target server --unlock" 203 | ) 204 | 205 | closureList = client.succeed("nix-store -qR {}".format(manifest)).split("\n") 206 | testService1 = [c for c in closureList if "-testService1" in c][0] 207 | 208 | # Use the echo type to activate a service. 209 | # We use the testService1 service defined in the manifest earlier 210 | # This test should succeed. 211 | client.succeed( 212 | "${env} disnix-nixops-client --target server --activate --arguments foo=foo --arguments bar=bar --type echo {}".format( 213 | testService1 214 | ) 215 | ) 216 | 217 | # Deactivate the same service using the echo type. This test should succeed. 218 | client.succeed( 219 | "${env} disnix-nixops-client --target server --deactivate --arguments foo=foo --arguments bar=bar --type echo {}".format( 220 | testService1 221 | ) 222 | ) 223 | 224 | # Deactivate the same service using the echo type. This test should succeed. 225 | client.succeed( 226 | "${env} disnix-nixops-client --target server --deactivate --arguments foo=foo --arguments bar=bar --type echo {}".format( 227 | testService1 228 | ) 229 | ) 230 | 231 | # Capture config test. We capture a config and the tempfile should 232 | # contain one property: "foo" = "bar"; 233 | client.succeed( 234 | "${env} disnix-nixops-client --target server --capture-config | grep '\"foo\" = \"bar\"'" 235 | ) 236 | 237 | # Shell test. We run a shell session in which we create a tempfile, 238 | # then we check whether the file exists and contains 'foo' 239 | client.succeed( 240 | "${env} disnix-nixops-client --target server --shell --arguments foo=foo --arguments bar=bar --type echo --command 'echo $foo > /tmp/tmpfile' {}".format( 241 | testService1 242 | ) 243 | ) 244 | server.succeed("grep 'foo' /tmp/tmpfile") 245 | ''; 246 | } 247 | -------------------------------------------------------------------------------- /tests/snapshots/distribution-reverse.nix: -------------------------------------------------------------------------------- 1 | {infrastructure}: 2 | 3 | { 4 | testService1 = [ infrastructure.testtarget2 ]; 5 | testService2 = [ infrastructure.testtarget1 ]; 6 | } 7 | -------------------------------------------------------------------------------- /tests/snapshots/distribution-simple.nix: -------------------------------------------------------------------------------- 1 | {infrastructure}: 2 | 3 | { 4 | testService1 = [ infrastructure.testtarget1 ]; 5 | testService2 = [ infrastructure.testtarget2 ]; 6 | } 7 | -------------------------------------------------------------------------------- /tests/snapshots/infrastructure.nix: -------------------------------------------------------------------------------- 1 | { 2 | testtarget1 = { 3 | hostname = "testtarget1"; 4 | supportedTypes = [ "echo" "process" "wrapper" ]; 5 | 6 | meta = { 7 | description = "The first test target"; 8 | }; 9 | }; 10 | 11 | testtarget2 = { 12 | hostname = "testtarget2"; 13 | supportedTypes = [ "echo" "process" "wrapper" ]; 14 | 15 | meta = { 16 | description = "The second test target"; 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /tests/snapshots/services-state.nix: -------------------------------------------------------------------------------- 1 | {distribution, invDistribution, system, pkgs}: 2 | 3 | let 4 | dysnomia = builtins.storePath (builtins.getEnv "dysnomia"); 5 | 6 | wrapper = import ./wrapper.nix { 7 | inherit dysnomia; 8 | inherit (pkgs) stdenv; 9 | }; 10 | in 11 | rec { 12 | testService1 = rec { 13 | name = "testService1"; 14 | pkg = wrapper { inherit name; }; 15 | dependsOn = {}; 16 | type = "wrapper"; 17 | deployState = true; 18 | }; 19 | 20 | testService2 = rec { 21 | name = "testService2"; 22 | pkg = wrapper { inherit name; }; 23 | dependsOn = {}; 24 | type = "wrapper"; 25 | deployState = true; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tests/snapshots/wrapper.nix: -------------------------------------------------------------------------------- 1 | {stdenv, dysnomia}: 2 | {name ? "wrapper"}: 3 | 4 | stdenv.mkDerivation { 5 | inherit name; 6 | buildCommand = '' 7 | mkdir -p $out/bin 8 | cat > $out/bin/wrapper << "EOF" 9 | #! ${stdenv.shell} -e 10 | 11 | source ${dysnomia}/share/dysnomia/util 12 | 13 | composeUtilityVariables "wrapper" "${name}" $3 14 | 15 | case "$1" in 16 | activate) 17 | if [ ! -d /var/db/${name} ] 18 | then 19 | mkdir -p /var/db/${name} 20 | echo 0 > /var/db/${name}/state 21 | fi 22 | markComponentAsActive 23 | ;; 24 | deactivate) 25 | markComponentAsGarbage 26 | ;; 27 | snapshot) 28 | tmpdir=$(mktemp -d) 29 | cd $tmpdir 30 | 31 | cp /var/db/${name}/state . 32 | 33 | hash=$(cat state | sha256sum) 34 | hash=''${hash:0:64} 35 | 36 | snapshotsPath=$(composeSnapshotsPath) 37 | 38 | if [ -d $snapshotsPath/$hash ] 39 | then 40 | rm -Rf $tmpdir 41 | else 42 | mkdir -p $snapshotsPath/$hash 43 | mv state $snapshotsPath/$hash 44 | rmdir $tmpdir 45 | fi 46 | 47 | createGenerationSymlink $hash 48 | ;; 49 | restore) 50 | lastSnapshot=$(determineLastSnapshot) 51 | 52 | if [ "$lastSnapshot" != "" ] 53 | then 54 | cp $lastSnapshot/state /var/db/${name} 55 | fi 56 | ;; 57 | collect-garbage) 58 | if componentMarkedAsGarbage 59 | then 60 | rm /var/db/${name}/state 61 | rmdir /var/db/${name} 62 | unmarkComponentAsGarbage 63 | fi 64 | ;; 65 | esac 66 | EOF 67 | 68 | chmod +x $out/bin/wrapper 69 | ''; 70 | } 71 | -------------------------------------------------------------------------------- /version: -------------------------------------------------------------------------------- 1 | 0.9.4 --------------------------------------------------------------------------------