Initial commit
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 21 Jul 2020 23:16:01 +0000 (01:16 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Tue, 21 Jul 2020 23:16:01 +0000 (01:16 +0200)
18 files changed:
shells/README.md [new file with mode: 0644]
shells/ipython.nix [new file with mode: 0644]
shells/mysql.nix [new file with mode: 0644]
shells/postgresql.nix [new file with mode: 0644]
shells/sub_bash.nix [new file with mode: 0644]
vms/Makefile [new file with mode: 0644]
vms/README [new file with mode: 0644]
vms/configuration.nix [new file with mode: 0644]
vms/images.nix [new file with mode: 0644]
vms/test_django/manage.py [new file with mode: 0755]
vms/test_django/test_django/__init__.py [new file with mode: 0644]
vms/test_django/test_django/__pycache__/__init__.cpython-38.pyc [new file with mode: 0644]
vms/test_django/test_django/__pycache__/settings.cpython-38.pyc [new file with mode: 0644]
vms/test_django/test_django/__pycache__/urls.cpython-38.pyc [new file with mode: 0644]
vms/test_django/test_django/__pycache__/wsgi.cpython-38.pyc [new file with mode: 0644]
vms/test_django/test_django/settings.py [new file with mode: 0644]
vms/test_django/test_django/urls.py [new file with mode: 0644]
vms/test_django/test_django/wsgi.py [new file with mode: 0644]

diff --git a/shells/README.md b/shells/README.md
new file mode 100644 (file)
index 0000000..2eeef76
--- /dev/null
@@ -0,0 +1,3 @@
+This directory regroups regularly-accessed nix-shells that require (or
+not) a bit of configuration to run and may not be trivial to write from
+scratch.
diff --git a/shells/ipython.nix b/shells/ipython.nix
new file mode 100644 (file)
index 0000000..c04a08f
--- /dev/null
@@ -0,0 +1,4 @@
+with import <nixpkgs> {};
+mkShell {
+  buildInputs = [ (python3.withPackages (ps: [ ps.ipython ])) ];
+}
diff --git a/shells/mysql.nix b/shells/mysql.nix
new file mode 100644 (file)
index 0000000..58428ac
--- /dev/null
@@ -0,0 +1,26 @@
+with import <nixpkgs> {};
+  mkShell {
+    buildInputs = [ mariadb ];
+    shellHook = ''
+      export MARIADBHOST=$PWD/mysql
+      export LANG=en_US.UTF-8;
+      export LOCALE_ARCHIVE=${glibcLocales}/lib/locale/locale-archive;
+      export MYSQL_UNIX_PORT=$MARIADBHOST/mysql.sock
+      mkdir -p $MARIADBHOST
+      cat > $MARIADBHOST/my.cnf <<EOF
+      [mysqld]
+      skip-networking
+      datadir=$MARIADBHOST
+      socket=$MARIADBHOST/mysql.sock
+      EOF
+      echo 'Initializing mysql database...'
+      mysql_install_db --defaults-file=$MARIADBHOST/my.cnf --datadir=$MARIADBHOST --basedir=${mariadb} > $MARIADBHOST/LOG 2>&1
+      mysqld --defaults-file=$MARIADBHOST/my.cnf --datadir=$MARIADBHOST --basedir=${mariadb} --pid-file=$MARIADBHOST/mariadb.pid >> $MARIADBHOST/LOG 2>&1 &
+      finish() {
+          mysqladmin shutdown
+          rm -rf "$MARIADBHOST";
+      }
+      trap finish EXIT
+    '';
+  }
+
diff --git a/shells/postgresql.nix b/shells/postgresql.nix
new file mode 100644 (file)
index 0000000..4f7bdc4
--- /dev/null
@@ -0,0 +1,26 @@
+with import <nixpkgs> {};
+  mkShell {
+    buildInputs = [ postgresql_11 glibcLocales ];
+    shellHook = ''
+            export PGDB="dummy";
+            export PGDATA=$PWD/postgres
+            export PGHOST=$PWD/postgres
+            export PGPORT=5432
+            export LOG_PATH=$PWD/postgres/LOG
+            export PGDATABASE=postgres
+            export DATABASE_URL="postgresql:///postgres?host=$PGDATA"
+            export LANG=en_US.UTF-8;
+            export LOCALE_ARCHIVE=${glibcLocales}/lib/locale/locale-archive;
+            mkdir -p $PGDATA
+            echo 'Initializing postgresql database...'
+            initdb $PGDATA --auth=trust >/dev/null
+            pg_ctl start -w -l $LOG_PATH -o "-c synchronous_commit=off -c listen_addresses= -c unix_socket_directories=$PGDATA"
+            createdb "$PGDB";
+            finish() {
+                pg_ctl stop -m fast;
+                rm -rf "$PGDATA";
+            }
+            trap finish EXIT
+    '';
+  }
+
diff --git a/shells/sub_bash.nix b/shells/sub_bash.nix
new file mode 100644 (file)
index 0000000..656b385
--- /dev/null
@@ -0,0 +1,16 @@
+# run with
+# nix-shell shell.nix --run 'touch in ; tail -f in | bash & echo $! > pid'
+# and then send commands with
+# echo 'compute_me "1 + 3"' >> in
+{ pkgs ? import <nixpkgs> {} }:
+pkgs.mkShell {
+  buildInputs = [ pkgs.bc ];
+  shellHook = ''
+    compute_me() {
+      echo "$1" | bc;
+    }
+    export -f compute_me
+
+    echo "I’m ready"
+    '';
+}
diff --git a/vms/Makefile b/vms/Makefile
new file mode 100644 (file)
index 0000000..3306b52
--- /dev/null
@@ -0,0 +1,23 @@
+.PHONY: run_light
+run_light:
+       $(shell nix-build images.nix --no-out-link -A light)
+
+.PHONY: run_standalone
+run_standalone:
+       $(shell nix-build images.nix --no-out-link -A standalone)
+
+.PHONY: run_docker
+run_docker:
+       $(shell nix-build images.nix --no-out-link -A docker)
+
+.PHONY: build_light
+build_light:
+       nix-build images.nix --no-out-link -A light.eval
+
+.PHONY: build_standalone
+build_standalone:
+       nix-build images.nix --no-out-link -A standalone.eval
+
+.PHONY: build_docker
+build_docker:
+       nix-build images.nix --no-out-link -A docker.eval
diff --git a/vms/README b/vms/README
new file mode 100644 (file)
index 0000000..d918d19
--- /dev/null
@@ -0,0 +1,7 @@
+This directory regroups several ways to run a VM, all building the same configuration.nix file
+- A light VM to run with QEMU binding to the host store
+- A standalone VM to run with QEMU
+- A docker VM
+
+In last two cases, you may build an image or directly execute it (see
+Makefile)
diff --git a/vms/configuration.nix b/vms/configuration.nix
new file mode 100644 (file)
index 0000000..c6e2cdf
--- /dev/null
@@ -0,0 +1,25 @@
+{ pkgs, ... }:
+{
+  config = {
+    users.users.root.password = "";
+    users.mutableUsers = false;
+
+    environment.systemPackages = [
+      pkgs.curl
+    ];
+    systemd.services.django-hello-world = {
+      description = "An example django app";
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+
+      preStart = "rm -rf /var/lib/django_app/test_app && cp -a ${./test_django} /var/lib/django_app/test_app";
+      script =
+        let pythonWithDjango = pkgs.python3.withPackages (p: [ p.django ]);
+        in "cd /var/lib/django_app/test_app && ${pythonWithDjango}/bin/python manage.py runserver";
+      serviceConfig = {
+        WorkingDirectory = "/var/lib/django_app";
+        StateDirectory = "django_app";
+      };
+    };
+  };
+}
diff --git a/vms/images.nix b/vms/images.nix
new file mode 100644 (file)
index 0000000..fd6c967
--- /dev/null
@@ -0,0 +1,134 @@
+let
+  pkgs = import <nixpkgs> {};
+  lib = pkgs.lib;
+  toEval = modules:
+    import <nixpkgs/nixos/lib/eval-config.nix> {
+      system = pkgs.system;
+      modules = [ ./configuration.nix ] ++ modules;
+    };
+  modules = {
+    docker = [
+      {
+        config = {
+          boot.isContainer = true;
+          system.activationScripts.installInitScript = ''
+            ln -fs $systemConfig/init /init
+          '';
+        };
+      }
+    ];
+    light = [
+      { config.virtualisation.graphics = false; }
+      <nixpkgs/nixos/modules/virtualisation/qemu-vm.nix>
+    ];
+    standalone = [
+      {
+        config = {
+          fileSystems."/" = {
+            device = "/dev/disk/by-label/nixos";
+            fsType = "ext4";
+            autoResize = true;
+          };
+
+          boot = {
+            kernelParams = [ "console=ttyS0" ];
+            loader = {
+              timeout = 0;
+              grub.device = "/dev/xvda";
+              grub.configurationLimit = 0;
+            };
+
+            initrd = {
+              network.enable = true;
+            };
+          };
+
+          services.udisks2.enable = false;
+        };
+      }
+    ];
+  };
+  evals = {
+    light = (toEval modules.light).config.system.build.vm;
+    docker =
+      # inspired from
+      # https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/docker-image.nix
+      let
+        eval = toEval modules.docker;
+      in
+        pkgs.callPackage <nixpkgs/nixos/lib/make-system-tarball.nix> {
+          contents = [
+            {
+              source = "${eval.config.system.build.toplevel}/.";
+              target = "./";
+            }
+          ];
+          extraArgs = "--owner=0";
+
+          # Add init script to image
+          storeContents = map (x: { object = x; symlink = "none"; }) [
+            eval.config.system.build.toplevel
+            pkgs.stdenv
+          ];
+
+          # Some container managers like lxc need these
+          extraCommands = "mkdir -p proc sys dev";
+        };
+    standalone =
+      let
+        eval = toEval modules.standalone;
+        name = "nixos-${eval.config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}";
+      in
+        import <nixpkgs/nixos/lib/make-disk-image.nix> {
+          inherit lib name pkgs;
+          config = eval.config;
+          contents = [];
+          diskSize = 2048;
+          format = "qcow2";
+          postVM = ''
+            extension=''${diskImage##*.}
+            friendlyName=$out/${name}.$extension
+            mv "$diskImage" "$friendlyName"
+            diskImage=$friendlyName
+
+            mkdir -p $out/nix-support
+
+            ${pkgs.jq}/bin/jq -n \
+              --arg label ${lib.escapeShellArg eval.config.system.nixos.label} \
+              --arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
+              --arg logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
+              --arg file "$diskImage" \
+              '$ARGS.named' \
+              > $out/nix-support/image-info.json
+          '';
+        };
+  };
+  scripts = {
+    standalone = pkgs.writeScript "run" ''
+      #!${pkgs.stdenv.shell}
+
+      file=$(cat ${evals.standalone}/nix-support/image-info.json | jq -r .file)
+      cp $file ./nixos.qcow2
+      chmod u+w nixos.qcow2
+
+      trap "rm -f nixos.qcow2" EXIT
+      ${pkgs.qemu}/bin/qemu-system-x86_64 -nographic --cpu host --enable-kvm -hda nixos.qcow2
+    '';
+    light = pkgs.writeScript "run" ''
+      #!${pkgs.stdenv.shell}
+
+      trap "rm -f nixos.qcow2" EXIT
+      ${evals.light}/bin/run-nixos-vm
+    '';
+    docker = pkgs.writeScript "run" ''
+      #!${pkgs.stdenv.shell}
+
+      docker import ${evals.docker}/tarball/nixos-system-*.tar.xz nixos-docker
+      cid=$(docker run --rm --privileged --detach nixos-docker /init)
+      trap "docker stop $cid" EXIT
+      sleep 10
+      docker exec -it $cid /run/current-system/sw/bin/bash
+    '';
+  };
+in
+  lib.mapAttrs (name: v: v // { run = scripts.${name}; eval = evals.${name}; modules = modules.${name};}) scripts
diff --git a/vms/test_django/manage.py b/vms/test_django/manage.py
new file mode 100755 (executable)
index 0000000..3908dee
--- /dev/null
@@ -0,0 +1,21 @@
+#!/nix/store/f87w21b91cws0wbsvyfn5vnlyv491czi-python3-3.8.3/bin/python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_django.settings')
+    try:
+        from django.core.management import execute_from_command_line
+    except ImportError as exc:
+        raise ImportError(
+            "Couldn't import Django. Are you sure it's installed and "
+            "available on your PYTHONPATH environment variable? Did you "
+            "forget to activate a virtual environment?"
+        ) from exc
+    execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/vms/test_django/test_django/__init__.py b/vms/test_django/test_django/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/vms/test_django/test_django/__pycache__/__init__.cpython-38.pyc b/vms/test_django/test_django/__pycache__/__init__.cpython-38.pyc
new file mode 100644 (file)
index 0000000..34a31c9
Binary files /dev/null and b/vms/test_django/test_django/__pycache__/__init__.cpython-38.pyc differ
diff --git a/vms/test_django/test_django/__pycache__/settings.cpython-38.pyc b/vms/test_django/test_django/__pycache__/settings.cpython-38.pyc
new file mode 100644 (file)
index 0000000..bc32dc4
Binary files /dev/null and b/vms/test_django/test_django/__pycache__/settings.cpython-38.pyc differ
diff --git a/vms/test_django/test_django/__pycache__/urls.cpython-38.pyc b/vms/test_django/test_django/__pycache__/urls.cpython-38.pyc
new file mode 100644 (file)
index 0000000..ee44baa
Binary files /dev/null and b/vms/test_django/test_django/__pycache__/urls.cpython-38.pyc differ
diff --git a/vms/test_django/test_django/__pycache__/wsgi.cpython-38.pyc b/vms/test_django/test_django/__pycache__/wsgi.cpython-38.pyc
new file mode 100644 (file)
index 0000000..8e5eb2b
Binary files /dev/null and b/vms/test_django/test_django/__pycache__/wsgi.cpython-38.pyc differ
diff --git a/vms/test_django/test_django/settings.py b/vms/test_django/test_django/settings.py
new file mode 100644 (file)
index 0000000..6d6cb48
--- /dev/null
@@ -0,0 +1,120 @@
+"""
+Django settings for test_django project.
+
+Generated by 'django-admin startproject' using Django 2.2.13.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.2/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '#mvm7ddn4qmsr94a5n-bs#q88&=x_+f(x&dzg!!@@g1!0ibi0f'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'test_django.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'test_django.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.2/howto/static-files/
+
+STATIC_URL = '/static/'
diff --git a/vms/test_django/test_django/urls.py b/vms/test_django/test_django/urls.py
new file mode 100644 (file)
index 0000000..9a2afd8
--- /dev/null
@@ -0,0 +1,21 @@
+"""test_django URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+    https://docs.djangoproject.com/en/2.2/topics/http/urls/
+Examples:
+Function views
+    1. Add an import:  from my_app import views
+    2. Add a URL to urlpatterns:  path('', views.home, name='home')
+Class-based views
+    1. Add an import:  from other_app.views import Home
+    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
+Including another URLconf
+    1. Import the include() function: from django.urls import include, path
+    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+
+urlpatterns = [
+    path('admin/', admin.site.urls),
+]
diff --git a/vms/test_django/test_django/wsgi.py b/vms/test_django/test_django/wsgi.py
new file mode 100644 (file)
index 0000000..984650c
--- /dev/null
@@ -0,0 +1,16 @@
+"""
+WSGI config for test_django project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'test_django.settings')
+
+application = get_wsgi_application()