aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--genenetwork-local-container.scm492
-rwxr-xr-xgenenetwork-local-container.sh81
2 files changed, 573 insertions, 0 deletions
diff --git a/genenetwork-local-container.scm b/genenetwork-local-container.scm
new file mode 100644
index 0000000..1b683ea
--- /dev/null
+++ b/genenetwork-local-container.scm
@@ -0,0 +1,492 @@
+;;; genenetwork-machines --- Guix configuration for genenetwork machines
+;;; Copyright © 2025 Munyoki Kilyungi <me@bonfacemunyoki.com>
+;;;
+;;; This file is part of genenetwork-machines.
+;;;
+;;; genenetwork-machines is free software: you can redistribute it
+;;; and/or modify it under the terms of the GNU General Public License
+;;; as published by the Free Software Foundation, either version 3 of
+;;; the License, or (at your option) any later version.
+;;;
+;;; genenetwork-machines is distributed in the hope that it will be
+;;; useful, but WITHOUT ANY WARRANTY; without even the implied
+;;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+;;; See the GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with genenetwork-machines. If not, see
+;;; <https://www.gnu.org/licenses/>.
+
+;;; This is the production genenetwork container currently deployed on
+;;; tux04.
+
+(use-modules (gnu)
+ (genenetwork services genenetwork)
+ (gnu build linux-container)
+ ((gn packages genenetwork) #:select (genenetwork2 genenetwork3 gn-auth gn-libs))
+ ((gnu packages admin) #:select (shepherd shadow))
+ ((gnu packages certs) #:select (nss-certs))
+ ((gnu packages bash) #:select (bash))
+ ((gnu packages check) #:select (python-pylint python-hypothesis))
+ ((gnu packages python-check) #:select (python-mypy python-mypy-extensions))
+ ((gnu packages python-web) #:select (gunicorn python-flask))
+ ((gnu packages version-control) #:select (git-minimal))
+ ((gn packages guile) #:select (gn-guile))
+ (gn services databases)
+ (gnu services databases)
+ (guix modules)
+ (gnu services shepherd)
+ (guix search-paths)
+ (guix least-authority)
+ (guix packages)
+ (guix profiles)
+ (guix records)
+ (forge socket)
+ (forge utils)
+ (srfi srfi-1)
+ (ice-9 match))
+
+(define-record-type* <genenetwork-configuration>
+ genenetwork-configuration make-genenetwork-configuration
+ genenetwork-configuration?
+ (gn2-port genenetwork-configuration-gn2-port
+ (default 8082))
+ (gn3-port genenetwork-configuration-gn3-port
+ (default 8083))
+ (gn-auth-port genenetwork-configuration-gn-auth-port
+ (default 8084))
+ (gn2-secrets genenetwork-configuration-gn2-secrets
+ (default "/etc/genenetwork/conf/gn2/secrets.py"))
+ (gn3-secrets genenetwork-configuration-gn3-secrets
+ (default "/etc/genenetwork/conf/gn3/secrets"))
+ (gn-auth-secrets genenetwork-configuration-gn-auth-secrets
+ (default "/etc/genenetwork"))
+ (genotype-files genenetwork-configuration-genotype-files
+ (default "/var/genenetwork/genotype-files"))
+ (sparql-endpoint genenetwork-configuration-sparql-endpoint
+ (default "http://localhost:7082/sparql"))
+ (data-directory genenetwork-data-directory
+ (default "/var/genenetwork"))
+ (xapian-db-path genenetwork-xapian-db-path
+ (default "/var/lib/xapian"))
+ (auth-db-path genenetwork-auth-db-path
+ (default "/var/genenetwork/auth.db"))
+ (llm-db-path genenetwork-llm-db-path
+ (default "/var/lib/genenetwork-sqlite/llm.db"))
+ (gn-guile-port genenetwork-configuration-gn-guile-port
+ (default 8091))
+ (gn-doc-git-checkout genenetwork-configuration-gn-doc-git-checkout
+ (default "/var/lib/gn-docs")))
+
+(define (genenetwork2-gexp config)
+ "Return a G-expression that runs the latest genenetwork2 development
+server described by CONFIG, a <genenetwork-configuration> object."
+ (match-record config <genenetwork-configuration>
+ (gn2-port gn3-port genotype-files)
+ (with-packages (list coreutils git-minimal gunicorn nss-certs)
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils)
+ (ice-9 match))
+
+ ;; Override the genenetwork3 used by genenetwork2.
+ (setenv "GN3_PYTHONPATH" "/genenetwork3")
+ ;; Set other environment variables required by
+ ;; genenetwork2.
+ (setenv "GN2_PROFILE" #$(profile
+ (content (package->development-manifest genenetwork2))
+ (allow-collisions? #t)))
+ (setenv
+ "GN2_SETTINGS"
+ #$(mixed-text-file "gn2.conf"
+ "GN2_SECRETS=\"/etc/genenetwork/conf/gn2/secrets.py\"\n"
+ "AI_SEARCH_ENABLED=True\n"
+ "GN3_LOCAL_URL=\""
+ (string-append "http://localhost:"
+ (number->string gn3-port))
+ "\"\n"
+ "GN_SERVER_URL=\"http://localhost:8083/api/\"\n"
+ "AUTH_SERVER_URL=\"http://localhost:8084/\"\n"
+ "SQL_URI=\"mysql://webqtlout:webqtlout@localhost/db_webqtl?unix_socket=/run/mysqld/mysqld.sock\"\n"
+ "SSL_PRIVATE_KEY=\"/etc/genenetwork/conf/gn2/private.pem\"\n"
+ "AUTH_SERVER_SSL_PUBLIC_KEY=\"/etc/genenetwork/conf/gn-auth/clients-public-keys/gn-auth.pem\"\n"))
+
+ ;; Start genenetwork2.
+ (with-directory-excursion "/genenetwork2"
+ (invoke #$(file-append bash "/bin/sh")
+ "bin/genenetwork2" "gn2/default_settings.py" "-gunicorn-dev")))))))
+
+(define (genenetwork3-gexp config)
+ "Return a G-expression that runs the latest genenetwork3 development
+server described by CONFIG, a <genenetwork-configuration> object."
+ (match-record config <genenetwork-configuration>
+ (gn3-port gn3-secrets sparql-endpoint data-directory xapian-db-path auth-db-path llm-db-path)
+ (with-manifest (package->development-manifest genenetwork3)
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils)
+ (ice-9 match))
+
+ ;; Configure genenetwork3.
+ (setenv "GN3_CONF"
+ #$(mixed-text-file "gn3.conf"
+ "SPARQL_ENDPOINT=\"" sparql-endpoint "\"\n"
+ "DATA_DIR=\"" data-directory "\"\n"
+ "AUTH_SERVER_URL=\"http://localhost:8084/\"\n"
+ "XAPIAN_DB_PATH=\"" xapian-db-path "\"\n"
+ "AUTH_DB=\"" auth-db-path "\"\n"
+ "LLM_DB_PATH=\"" llm-db-path "\"\n"))
+ (setenv "HOME" "/tmp")
+ (setenv "GN3_SECRETS" #$gn3-secrets)
+ (setenv "RSCRIPT" #$(file-append
+ (profile
+ (content (package->development-manifest genenetwork3))
+ (allow-collisions? #t))
+ "/bin/Rscript"))
+ (setenv "FLASK_ENV" "development")
+ (setenv "FLASK_DEBUG" "1")
+ ;; Run genenetwork3.
+ (with-directory-excursion "/genenetwork3"
+ (invoke #$(file-append python-flask "/bin/flask")
+ "run"
+ #$(string-append "--port=" (number->string gn3-port)))))))))
+
+(define (gn-auth-gexp config)
+ "Return a G-expression that runs the latest gn-auth development
+server described by CONFIG, a <genenetwork-configuration> object."
+ (match-record config <genenetwork-configuration>
+ (gn-auth-port auth-db-path gn-auth-secrets)
+ (with-manifest (package->development-manifest gn-auth)
+ (with-packages (list git-minimal nss-certs)
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils)
+ (ice-9 match))
+ ;; Configure gn-auth.
+ (setenv "GN_AUTH_CONF"
+ #$(mixed-text-file
+ "gn-auth.conf"
+ "LOGLEVEL=\"DEBUG\"\n"
+ "SQL_URI=\"mysql://webqtlout:webqtlout@localhost/db_webqtl?unix_socket=/run/mysqld/mysqld.sock\"\n"
+ "AUTH_DB=\"" auth-db-path "\"\n"
+ "GN_AUTH_SECRETS=\"/etc/genenetwork/conf/gn-auth/secrets.py\"\n"
+ "CLIENTS_SSL_PUBLIC_KEYS_DIR=\"/etc/genenetwork/conf/gn-auth/clients-public-keys/\"\n"
+ "SSL_PRIVATE_KEY=\"/etc/genenetwork/conf/gn-auth/private.pem\"\n"))
+ (setenv "HOME" "/tmp")
+ (setenv "AUTHLIB_INSECURE_TRANSPORT" "true")
+ ;; Run gn-auth.
+ (with-directory-excursion "/gn-auth"
+ (invoke #$(file-append gunicorn "/bin/gunicorn")
+ "-b" #$(string-append "localhost:" (number->string gn-auth-port))
+ "--workers" "8"
+ "gn_auth.wsgi:app"))))))))
+
+(define (genenetwork-activation config)
+ (match-record config <genenetwork-configuration>
+ (gn2-secrets gn3-secrets auth-db-path gn-auth-secrets)
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils))
+
+ ;; Set ownership of files.
+ (for-each (lambda (file)
+ (chown file
+ (passwd:uid (getpw "genenetwork"))
+ (passwd:gid (getpw "genenetwork"))))
+ (cons* #$gn3-secrets
+ (append (find-files #$gn2-secrets
+ #:directories? #t)
+ (find-files "/var/lib/gn-docs"
+ #:directories? #t)
+ (find-files #$(dirname auth-db-path)
+ #:directories? #t)
+ (find-files #$gn-auth-secrets
+ #:directories? #t))))
+ ;; Prevent other users from reading secret files.
+ (for-each (lambda (file)
+ (chmod file #o600))
+ (append (list #$gn3-secrets)
+ (find-files #$gn2-secrets
+ #:directories? #f)
+ (find-files #$gn-auth-secrets
+ #:directories? #f)))))))
+
+(define (gn-guile-gexp gn-guile-port)
+ (with-imported-modules '((guix build utils))
+ #~(begin
+ (use-modules (guix build utils))
+ (let ((current-repo-path (string-append (getcwd) "/gn-docs")))
+ (when (file-exists? current-repo-path)
+ (delete-file-recursively current-repo-path))
+ (setenv "CURRENT_REPO_PATH" current-repo-path)
+ (invoke #$(file-append git-minimal "/bin/git")
+ "clone" "--depth" "1" (getenv "CGIT_REPO_PATH")))
+ (invoke #$(file-append gn-guile "/bin/gn-guile")
+ (number->string #$gn-guile-port)))))
+
+
+(define (genenetwork-shepherd-services config)
+ "Return shepherd services to run the genenetwork development server
+described by CONFIG, a <genenetwork-configuration> object."
+ (match-record config <genenetwork-configuration>
+ (gn2-port gn3-port gn-auth-port genotype-files data-directory xapian-db-path gn2-secrets auth-db-path gn-auth-secrets llm-db-path gn-doc-git-checkout gn-guile-port)
+ (list (shepherd-service
+ (documentation "Run gn-guile server.")
+ (provision '(gn-guile))
+ (requirement '(networking))
+ (modules '((ice-9 match)
+ (srfi srfi-1)))
+ (start
+ (let* ((gn-guile-settings
+ `(("CGIT_REPO_PATH" ,gn-doc-git-checkout)
+ ("LC_ALL" "en_US.UTF-8")
+ ("GIT_COMMITTER_NAME" "genenetwork")
+ ("GIT_COMMITTER_EMAIL" "no-reply@git.genenetwork.org"))))
+ #~(make-forkexec-constructor
+ (list #$(least-authority-wrapper
+ (program-file "gn-guile"
+ (gn-guile-gexp gn-guile-port))
+ #:name "gn-guile-pola-wrapper"
+ #:preserved-environment-variables
+ (map first gn-guile-settings)
+ #:mappings (list (file-system-mapping
+ (source gn-doc-git-checkout)
+ (target source)
+ (writable? #t)))
+ #:namespaces (delq 'net %namespaces))
+ "127.0.0.1" #$(number->string gn-guile-port))
+ #:user "genenetwork"
+ #:group "genenetwork"
+ #:environment-variables
+ (map (match-lambda
+ ((spec value)
+ (string-append spec "=" value)))
+ '#$gn-guile-settings)
+ #:log-file "/var/log/gn-guile.log")))
+ (stop #~(make-kill-destructor)))
+ (shepherd-service
+ (documentation "Run GeneNetwork 2 development server.")
+ (provision '(genenetwork2))
+ ;; FIXME: The genenetwork2 service should depend on redis.
+ (requirement '(networking genenetwork3))
+ (modules '((guix search-paths)
+ (ice-9 match)
+ (srfi srfi-1)))
+ (start
+ (let* ((gn2-manifest (packages->manifest (list genenetwork2)))
+ (gn2-profile (profile
+ (content gn2-manifest)
+ (allow-collisions? #t)))
+ (gn2-settings
+ `(("SERVER_PORT" ,(number->string gn2-port))
+ ("GENENETWORK_FILES" ,genotype-files)
+ ("HOME" "/tmp")
+ ("LC_ALL" "en_US.UTF-8")
+ ("NO_REDIS" "no-redis")
+ ("RUST_BACKTRACE" "1"))))
+ (with-imported-modules (source-module-closure '((guix search-paths)))
+ #~(make-forkexec-constructor
+ (list #$(least-authority-wrapper
+ (program-file "genenetwork2"
+ (genenetwork2-gexp config))
+ #:name "genenetwork2-pola-wrapper"
+ #:preserved-environment-variables
+ (append '("REQUESTS_CA_BUNDLE")
+ (map first gn2-settings)
+ (map search-path-specification-variable
+ (manifest-search-paths gn2-manifest)))
+ ;; If we mapped only the mysqld.sock
+ ;; socket file, it would break when the
+ ;; external mysqld server is restarted.
+ #:mappings (list (file-system-mapping
+ (source genotype-files)
+ (target source))
+ (file-system-mapping
+ (source "/genenetwork2")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source "/run/mysqld")
+ (target source)
+ (writable? #t))
+ ;; XXXX: FIXME: R/Qtl generates
+ ;; files in "/tmp" and
+ ;; "/tmp/gn2". These files are
+ ;; accessed by gn3 for R/Qtl
+ ;; mapping
+ (file-system-mapping
+ (source "/tmp")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source gn2-secrets)
+ (target source)
+ (writable? #t)))
+ #:namespaces (delq 'net %namespaces))
+ "127.0.0.1" #$(number->string gn2-port))
+ #:user "genenetwork"
+ #:group "genenetwork"
+ #:environment-variables
+ (append
+ '("REQUESTS_CA_BUNDLE="
+ #$(file-append gn2-profile "/etc/ssl/certs/ca-certificates.crt"))
+ (map (match-lambda
+ ((spec . value)
+ (string-append (search-path-specification-variable spec)
+ "="
+ value)))
+ (evaluate-search-paths
+ (map sexp->search-path-specification
+ '#$(map search-path-specification->sexp
+ (manifest-search-paths gn2-manifest)))
+ (list #$gn2-profile)))
+ (map (match-lambda
+ ((spec value)
+ (string-append spec "=" value)))
+ '#$gn2-settings))
+ #:log-file "/var/log/genenetwork2.log"))))
+ (stop #~(make-kill-destructor)))
+ (shepherd-service
+ (documentation "Run GeneNetwork 3 development server.")
+ (provision '(genenetwork3))
+ (requirement '(networking))
+ (start #~(make-forkexec-constructor
+ (list #$(least-authority-wrapper
+ (program-file "genenetwork3"
+ (genenetwork3-gexp config))
+ #:name "genenetwork3-pola-wrapper"
+ #:mappings (list (file-system-mapping
+ (source "/genenetwork3")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source "/run/mysqld")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source "/tmp")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source data-directory)
+ (target source))
+ (file-system-mapping
+ (source xapian-db-path)
+ (target source))
+ (file-system-mapping
+ (source "/etc/genenetwork/conf/gn3")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source auth-db-path)
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source llm-db-path)
+ (target source)
+ (writable? #t)))
+ #:namespaces (delq 'net %namespaces))
+ "127.0.0.1" #$(number->string gn3-port))
+ #:user "genenetwork"
+ #:group "genenetwork"
+ #:log-file "/var/log/genenetwork3.log"))
+ (stop #~(make-kill-destructor)))
+ (shepherd-service
+ (documentation "Run gn-auth development server.")
+ (provision '(gn-auth))
+ (requirement '(networking))
+ (start #~(make-forkexec-constructor
+ (list #$(least-authority-wrapper
+ (program-file "gn-auth"
+ (gn-auth-gexp config))
+ #:name "gn-auth-pola-wrapper"
+ ;; If we mapped only the mysqld.sock
+ ;; socket file, it would break when the
+ ;; external mysqld server is restarted.
+ #:mappings (list (file-system-mapping
+ (source "/run/mysqld")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source "/gn-auth")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source "/run/mysqld")
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source data-directory)
+ (target source))
+ (file-system-mapping
+ (source auth-db-path)
+ (target source)
+ (writable? #t))
+ (file-system-mapping
+ (source gn-auth-secrets)
+ (target source)
+ (writable? #t)))
+ #:namespaces (delq 'net %namespaces))
+ "127.0.0.1" #$(number->string gn-auth-port))
+ #:user "genenetwork"
+ #:group "genenetwork"
+ #:log-file "/var/log/gn-auth.log"))
+ (stop #~(make-kill-destructor))))))
+
+(define %genenetwork-accounts
+ (list (user-group
+ (name "genenetwork")
+ (system? #t))
+ (user-account
+ (name "genenetwork")
+ (group "genenetwork")
+ (system? #t)
+ (comment "GeneNetwork user")
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin")))))
+
+
+(define genenetwork-service-type
+ (service-type
+ (name 'genenetwork)
+ (description "Run GeneNetwork development servers and CI.")
+ (extensions
+ (list (service-extension account-service-type
+ (const %genenetwork-accounts))
+ (service-extension activation-service-type
+ genenetwork-activation)
+ (service-extension shepherd-root-service-type
+ genenetwork-shepherd-services)))
+ (default-value (genenetwork-configuration))))
+
+
+(operating-system
+ (host-name "genenetwork-work-container")
+ (timezone "UTC")
+ (locale "en_US.utf8")
+ (bootloader (bootloader-configuration
+ (bootloader grub-bootloader)
+ (targets (list "/dev/sdX"))))
+ (file-systems %base-file-systems)
+ (users %base-user-accounts)
+ (sudoers-file
+ (mixed-text-file "sudoers"
+ "@include " %sudoers-specification
+ "\nacme ALL = NOPASSWD: " (file-append shepherd "/bin/herd") " restart nginx\n"))
+ (packages (cons* genenetwork2 python-hypothesis gn-auth
+ python-mypy python-mypy-extensions python-pylint
+ %base-packages))
+ (services (cons* (service virtuoso-service-type
+ (virtuoso-configuration
+ (server-port 7081)
+ (http-server-port 7082)
+ (dirs-allowed "/var/lib/virtuoso/data")
+ (database-file "/var/lib/virtuoso/genenetwork-virtuoso.db")
+ (transaction-file "/var/lib/virtuoso/genenetwork-virtuoso.trx")))
+ (service redis-service-type
+ (redis-configuration
+ (bind "127.0.0.1")
+ (port 6379)
+ (working-directory "/var/lib/redis")))
+ (service genenetwork-service-type)
+ %base-services)))
diff --git a/genenetwork-local-container.sh b/genenetwork-local-container.sh
new file mode 100755
index 0000000..07d0662
--- /dev/null
+++ b/genenetwork-local-container.sh
@@ -0,0 +1,81 @@
+#! /bin/sh -e
+
+# genenetwork-machines --- Guix configuration for genenetwork machines
+# Copyright © 2025 Munyoki Kilyungi <me@bonfacemunyoki.com>
+#
+# This file is part of genenetwork-machines.
+#
+# genenetwork-machines is free software: you can redistribute it
+# and/or modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, either version 3 of
+# the License, or (at your option) any later version.
+#
+# genenetwork-machines is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with genenetwork-machines. If not, see
+# <https://www.gnu.org/licenses/>.
+
+# Build and install genenetwork production container on tux02.
+
+system_directories=("$HOME"/genenetwork/var/log
+ "$HOME"/genenetwork/var/genenetwork
+ "$HOME"/genenetwork/etc/genenetwork/conf
+ "$HOME"/genenetwork/etc/genenetwork
+ "$HOME"/genenetwork/var/lib/redis
+ "$HOME"/genenetwork/var/lib/virtuoso
+ "$HOME"/genenetwork/var/lib/xapian
+ "$HOME"/genenetwork/var/lib/genenetwork-sqlite
+ "$HOME"/genenetwork/var/lib/genenetwork-gnqa
+ /tmp/local-container)
+
+for dir in "${system_directories[@]}"; do
+ if [[ ! -d $dir ]]; then
+ mkdir -p $dir
+ fi
+done
+
+gn_projects=(genenetwork2 genenetwork3)
+for project in "${gn_projects[@]}"; do
+ dir="${HOME}/genenetwork/${project}"
+ if [[ ! -d $dir ]]; then
+ git clone "git@github.com:genenetwork/${project}" $dir
+ fi
+done
+
+if [[ ! -d "${HOME}/genenetwork/gn-auth" ]]; then
+ git clone "https://git.genenetwork.org/gn-auth" "${HOME}/genenetwork/gn-auth"
+fi
+
+if [[ ! -d "${HOME}/genenetwork/gn-docs" ]]; then
+ git clone --bare "https://git.genenetwork.org/gn-docs" "${HOME}/genenetwork/gn-docs"
+fi
+
+container_script=$(guix system container \
+ --network \
+ --load-path=. \
+ --verbosity=3 \
+ --share="$HOME"/genenetwork/var/log=/var/log \
+ --share="$HOME"/genenetwork/var/genenetwork=/var/genenetwork \
+ --share="$HOME"/genenetwork/etc/genenetwork/conf=/etc/genenetwork/conf \
+ --share="$HOME"/genenetwork/etc/genenetwork=/etc/genenetwork \
+ --share="$HOME"/genenetwork/var/lib/redis=/var/lib/redis \
+ --share="$HOME"/genenetwork/var/lib/virtuoso/=/var/lib/virtuoso \
+ --share="$HOME"/genenetwork/genenetwork2=/genenetwork2 \
+ --share="$HOME"/genenetwork/genenetwork3=/genenetwork3 \
+ --share="$HOME"/genenetwork/gn-auth=/gn-auth \
+ --share="$HOME"/genenetwork/var/lib/xapian=/var/lib/xapian \
+ --share="$HOME"/genenetwork/var/lib/genenetwork-sqlite=/var/lib/genenetwork-sqlite \
+ --share="$HOME"/genenetwork/var/lib/genenetwork-gnqa=/var/lib/genenetwork-gnqa \
+ --share=/tmp/local-container=/tmp \
+ --share="$HOME"/genenetwork/gn-docs=/var/lib/gn-docs \
+ --share=/run/mysqld=/run/mysqld \
+ genenetwork-local-container.scm)
+
+echo $container_script
+sudo ln --force --symbolic $container_script /usr/local/bin/genenetwork-local-container
+sudo ln --force --symbolic /usr/local/bin/genenetwork-local-container /var/guix/gcroots
+