diff --git a/modules/services/web/rails/default.nix b/modules/services/web/rails/default.nix index 9ac135b..8abfb29 100644 --- a/modules/services/web/rails/default.nix +++ b/modules/services/web/rails/default.nix @@ -25,7 +25,7 @@ let "${app.domain}" = { forceSSL = config.phoebe.security.enable; enableACME = config.phoebe.security.enable; - root = "${app.package}/share/${app.name}/public"; + root = "${funcs.appLink app}/share/${app.name}/public"; locations = { "/assets/" = { diff --git a/modules/services/web/rails/functions.nix b/modules/services/web/rails/functions.nix index 153506c..ba50604 100644 --- a/modules/services/web/rails/functions.nix +++ b/modules/services/web/rails/functions.nix @@ -10,6 +10,10 @@ rec { # Where a Rails application lives: home = name: "${base}/${name}"; + ############################################################################## + # Path to where the app is actually installed: + appLink = app: "${app.home}/package"; + ############################################################################## # Is PostgreSQL local? localpg = config.phoebe.services.postgresql.enable; diff --git a/modules/services/web/rails/options.nix b/modules/services/web/rails/options.nix index 322f39c..71bbbdc 100644 --- a/modules/services/web/rails/options.nix +++ b/modules/services/web/rails/options.nix @@ -116,6 +116,21 @@ let ''; }; + deployedExternally = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + When true, system activation will not override the app link + in the home directory. However, it will be created if missing. + + This is useful if you want to deploy your Rails application + using some external tool. In the Phoebe scripts directory + there is an example script for deploying with + nix-copy-closure. + ''; + }; + home = mkOption { type = types.path; description = "The directory where the application is deployed to."; diff --git a/modules/services/web/rails/systemd.nix b/modules/services/web/rails/systemd.nix index 498a298..a7fd347 100644 --- a/modules/services/web/rails/systemd.nix +++ b/modules/services/web/rails/systemd.nix @@ -52,18 +52,22 @@ let app.afterServices; preStart = optionalString service.isMain '' + # Link the package into the application's home directory: + if [ ! -e "${funcs.appLink app}" ] || [ "${toString app.deployedExternally}" -ne 1 ]; then + ln -nfs "${app.package}" "${funcs.appLink app}" + fi + # Prepare the config directory: rm -rf ${app.home}/config mkdir -p ${app.home}/{config,log,tmp,db,state} - - cp -rf ${app.package}/share/${app.name}/config.dist/* ${app.home}/config/ - cp ${app.package}/share/${app.name}/db/schema.rb.dist ${app.home}/db/schema.rb + cp -rf ${funcs.appLink app}/share/${app.name}/config.dist/* ${app.home}/config/ + cp ${funcs.appLink app}/share/${app.name}/db/schema.rb.dist ${app.home}/db/schema.rb cp ${./database.yml} ${app.home}/config/database.yml cp ${app.database.passwordFile} ${app.home}/state/database.password # Additional set up for the home directory: mkdir -p ${app.home}/home - ln -nfs ${app.package}/share/${app.name} ${app.home}/home/app + ln -nfs ${funcs.appLink app}/share/${app.name} ${app.home}/home/app ln -nfs ${plib.attrsToShellExports "rails-${app.name}-env" (funcs.appEnv app)} ${app.home}/home/.env cp ${./profile.sh} ${app.home}/home/.profile chmod 0700 ${app.home}/home/.profile @@ -82,7 +86,7 @@ let # Migrate the database: ${pkgs.sudo}/bin/sudo --user=rails-${app.name} --login \ ${scripts.user}/bin/db-migrate.sh \ - -r ${app.package}/share/${app.name} \ + -r ${funcs.appLink app}/share/${app.name} \ -s ${app.home}/state ''; @@ -92,7 +96,7 @@ let ''; serviceConfig = { - WorkingDirectory = "${app.package}/share/${app.name}"; + WorkingDirectory = "-${funcs.appLink app}/share/${app.name}"; Restart = "on-failure"; TimeoutSec = "infinity"; # FIXME: what's a reasonable amount of time? Type = "simple"; diff --git a/scripts/deploy-rails-app.sh b/scripts/deploy-rails-app.sh new file mode 100755 index 0000000..e6e9da7 --- /dev/null +++ b/scripts/deploy-rails-app.sh @@ -0,0 +1,87 @@ +#!/bin/sh + +################################################################################ +# Example script to deploy a rails application: +set -e +set -u + +################################################################################ +option_base="/var/lib/rails" +option_app_name="" +option_host="" + +################################################################################ +usage() { + cat < -t [options] + + -h This message + -n NAME Application name + -p PATH Base path of Rails application (default: $option_base) + -t HOST SSH host to deploy to (e.g., root@example.com) +EOF +} + +################################################################################ +while getopts "hn:p:t:" o; do + case "${o}" in + h) usage + exit + ;; + + n) option_app_name=$OPTARG + ;; + + p) option_base=$OPTARG + ;; + + t) option_host=$OPTARG + ;; + + *) exit 1 + ;; + esac +done + +shift $((OPTIND-1)) + +################################################################################ +if [ ! -e default.nix ]; then + >&2 echo "ERROR: Run this from a directory that has a default.nix file" + exit 1 +fi + +################################################################################ +if [ -z "$option_app_name" ]; then + >&2 echo "ERROR: You must use the -n option to name the application" + exit 1 +fi + +################################################################################ +if [ -z "$option_host" ]; then + >&2 echo "ERROR: You must use the -t option to specify the host" + exit 1 +fi + +################################################################################ +if [ $# -ne 0 ]; then + >&2 echo "ERROR: invalid options given: $*" + exit 1 +fi + +################################################################################ +echo "==> Building application" +path=$(nix-build --quiet --no-out-link) + +echo "==> Uploading application to $option_host" +nix-copy-closure --use-substitutes --to "$option_host" "$path" + +# Create the GC root: +echo "==> Installing and activating application" +ssh "$option_host" \ + nix-store --add-root "$option_base/$option_app_name/package" \ + --indirect --realize --quiet "$path" + +# Restart the application: +echo "==> Restarting application" +ssh "$option_host" systemctl restart rails-"$option_app_name"-'\*'