From b62c49ecf786ba55db408e41bb37804b0a7b25be Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Wed, 14 Jan 2015 13:00:09 +0100 Subject: [PATCH 01/71] start tracking latest development in our new dev branch --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index c0cc7b7ec..71fedb3c4 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -32,7 +32,7 @@ RUN groupadd -r galaxy -g 450 && \ gpasswd -a galaxy docker # Download and update Galaxy to the latest stable release -RUN hg clone --rev latest_2015.01.13 https://bitbucket.org/galaxy/galaxy-central/ && \ +RUN hg clone --rev default https://bitbucket.org/galaxy/galaxy-central/ && \ cd /galaxy-central/ && \ rm /galaxy-central/.hg/ -rf && chown galaxy:galaxy /galaxy-central/ -R From 4517a494d729563dd08f27a1165ad21a59f4fbc3 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 16 Jan 2015 14:07:35 -0500 Subject: [PATCH 02/71] Derive image from toolshed/requirements. --- galaxy/Dockerfile | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 5b60add6f..94ff71847 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -2,7 +2,7 @@ # # VERSION Galaxy-central -FROM ubuntu:14.04 +FROM toolshed/requirements MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com @@ -11,19 +11,15 @@ MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com # * Enable the @natefoo magic # Web server infrastructure matching usegalaxy.org - supervisor, uwsgi, and nginx. -ENV DEBIAN_FRONTEND noninteractive - RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transport-https software-properties-common && \ apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 && \ sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" && \ apt-get update -qq && apt-get upgrade -y && \ add-apt-repository ppa:galaxyproject/nginx && apt-get -qq update && \ apt-get purge -y software-properties-common && \ - apt-get install --no-install-recommends -y autoconf automake build-essential gfortran cmake wget \ - git-core libatlas-base-dev libblas-dev liblapack-dev mercurial subversion python-dev pkg-config \ - openjdk-7-jre-headless python-setuptools python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv \ + apt-get install --no-install-recommends -y mercurial python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv wget \ nginx-extras uwsgi uwsgi-plugin-python supervisor lxc-docker slurm-llnl slurm-llnl-torque libswitch-perl \ - slurm-drmaa-dev zlib1g-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools && \ + slurm-drmaa-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN groupadd -r galaxy -g 450 && \ From fb8275e363dcb0003b87c1dc7cb8860194da19b4 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Wed, 28 Jan 2015 13:17:26 -0500 Subject: [PATCH 03/71] Optimize galaxy-central download. Don't download huge history just to throw it out - download just things in tip of release (much, much smaller than history due to some very large test files in the past). --- galaxy/Dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 94ff71847..cd280c32c 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -27,10 +27,11 @@ RUN groupadd -r galaxy -g 450 && \ mkdir /export/ /home/galaxy/ && chown -R galaxy:galaxy /home/galaxy /export/ && \ gpasswd -a galaxy docker -# Download and update Galaxy to the latest stable release -RUN hg clone --rev latest_2015.01.13 https://bitbucket.org/galaxy/galaxy-central/ && \ - cd /galaxy-central/ && \ - rm /galaxy-central/.hg/ -rf && chown galaxy:galaxy /galaxy-central/ -R + +# Download latest stable release of Galaxy. +ENV GALAXY_RELEASE latest_2015.01.13 +ENV GALAXY_ROOT /galaxy-central/ +RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R galaxy:galaxy $GALAXY_ROOT RUN mkdir /shed_tools && chown galaxy:galaxy /shed_tools From b21a1b7b44b53007eecdd13e97248e1dd1764780 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Wed, 28 Jan 2015 19:58:09 +0100 Subject: [PATCH 04/71] merge --- galaxy/Dockerfile | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index b9d95fe3c..cd280c32c 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -2,7 +2,7 @@ # # VERSION Galaxy-central -FROM ubuntu:14.04 +FROM toolshed/requirements MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com @@ -11,19 +11,15 @@ MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com # * Enable the @natefoo magic # Web server infrastructure matching usegalaxy.org - supervisor, uwsgi, and nginx. -ENV DEBIAN_FRONTEND noninteractive - RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transport-https software-properties-common && \ apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 && \ sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" && \ apt-get update -qq && apt-get upgrade -y && \ add-apt-repository ppa:galaxyproject/nginx && apt-get -qq update && \ apt-get purge -y software-properties-common && \ - apt-get install --no-install-recommends -y autoconf automake build-essential gfortran cmake wget \ - git-core libatlas-base-dev libblas-dev liblapack-dev mercurial subversion python-dev pkg-config \ - openjdk-7-jre-headless python-setuptools python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv \ + apt-get install --no-install-recommends -y mercurial python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv wget \ nginx-extras uwsgi uwsgi-plugin-python supervisor lxc-docker slurm-llnl slurm-llnl-torque libswitch-perl \ - slurm-drmaa-dev zlib1g-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools && \ + slurm-drmaa-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN groupadd -r galaxy -g 450 && \ @@ -31,10 +27,11 @@ RUN groupadd -r galaxy -g 450 && \ mkdir /export/ /home/galaxy/ && chown -R galaxy:galaxy /home/galaxy /export/ && \ gpasswd -a galaxy docker -# Download and update Galaxy to the latest stable release -RUN hg clone --rev default https://bitbucket.org/galaxy/galaxy-central/ && \ - cd /galaxy-central/ && \ - rm /galaxy-central/.hg/ -rf && chown galaxy:galaxy /galaxy-central/ -R + +# Download latest stable release of Galaxy. +ENV GALAXY_RELEASE latest_2015.01.13 +ENV GALAXY_ROOT /galaxy-central/ +RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R galaxy:galaxy $GALAXY_ROOT RUN mkdir /shed_tools && chown galaxy:galaxy /shed_tools From 573a57e0611dc228e921d729b63118068929b368 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 29 Jan 2015 10:06:39 -0500 Subject: [PATCH 05/71] Use ansible to configure the @natefoo stack. Enables reuse with other projects that are not explicitly Docker - such as [planemo-machine](https://github.com/jmchilton/planemo-machine) and perhaps down the road Cloudman. The ansible recipes are more parameterized as well - so by tweaking a couple variables one could end up with a very customized Docker image. Along those same lines - I have extracted some repeated values out of the `Dockerfile` into `ENV` variables as part of this commit. Two smaller changes include: - Move dev tools up into initial `apt-get` to keep images small. - Move nginx upload tmp to `/tmp` so it is outside Galaxy root. --- .gitmodules | 3 + galaxy/Dockerfile | 85 +++++++-------- galaxy/configure_slurm.py | 96 ----------------- galaxy/job_conf.xml | 21 ---- galaxy/proftpd.conf | 63 ----------- galaxy/provision.yml | 5 + galaxy/roles/galaxyprojectdotorg.galaxyextras | 1 + galaxy/startup.sh | 2 +- galaxy/supervisor.conf | 100 ------------------ 9 files changed, 47 insertions(+), 329 deletions(-) create mode 100644 .gitmodules delete mode 100644 galaxy/configure_slurm.py delete mode 100644 galaxy/job_conf.xml delete mode 100644 galaxy/proftpd.conf create mode 100644 galaxy/provision.yml create mode 160000 galaxy/roles/galaxyprojectdotorg.galaxyextras delete mode 100644 galaxy/supervisor.conf diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d8bd0a9db --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "galaxy/roles/galaxyproject.galaxyextras"] + path = galaxy/roles/galaxyprojectdotorg.galaxyextras + url = https://github.com/galaxyproject/ansible-galaxy-extras diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index cd280c32c..5252302db 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -15,25 +15,48 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 && \ sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" && \ apt-get update -qq && apt-get upgrade -y && \ - add-apt-repository ppa:galaxyproject/nginx && apt-get -qq update && \ + apt-add-repository -y ppa:ansible/ansible && \ + add-apt-repository ppa:galaxyproject/nginx && \ + apt-get -qq update && \ apt-get purge -y software-properties-common && \ apt-get install --no-install-recommends -y mercurial python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv wget \ nginx-extras uwsgi uwsgi-plugin-python supervisor lxc-docker slurm-llnl slurm-llnl-torque libswitch-perl \ - slurm-drmaa-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools && \ + slurm-drmaa-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools ansible \ + nano nmap lynx vim curl python-pip && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -RUN groupadd -r galaxy -g 450 && \ - useradd -u 451 -r -g galaxy -d /home/galaxy -c "Galaxy user" galaxy && \ - mkdir /export/ /home/galaxy/ && chown -R galaxy:galaxy /home/galaxy /export/ && \ - gpasswd -a galaxy docker - - # Download latest stable release of Galaxy. ENV GALAXY_RELEASE latest_2015.01.13 -ENV GALAXY_ROOT /galaxy-central/ -RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R galaxy:galaxy $GALAXY_ROOT +ENV GALAXY_ROOT /galaxy-central +# TODO: make this /etc/galaxy +ENV GALAXY_CONFIG_DIR /galaxy-central/config +ENV GALAXY_VIRTUALENV /home/galaxy/venv +ENV GALAXY_USER galaxy +ENV GALAXY_HOME /home/galaxy +ENV EXPORT_DIR /export + +RUN groupadd -r $GALAXY_USER -g 450 && \ + useradd -u 451 -r -g $GALAXY_USER -d $GALAXY_HOME -c "Galaxy user" $GALAXY_USER && \ + mkdir $EXPORT_DIR $GALAXY_HOME && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_HOME $EXPORT_DIR && \ + gpasswd -a $GALAXY_USER docker + +RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_ROOT + +# TODO: ensure virtualenv as part of galaxy role +RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" + +# Setup Galaxy configuration files. +RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_DIR/galaxy.ini && \ + cp $GALAXY_ROOT/config/reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" +ADD roles/ /tmp/ansible/roles +ADD provision.yml /tmp/ansible/provision.yml +RUN ansible-playbook /tmp/ansible/provision.yml --extra-vars galaxy_user_name=$GALAXY_USER --extra-vars galaxy_config_file=$GALAXY_CONFIG_DIR/galaxy.ini --tags=galaxyextras -c local && \ + apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +ADD roles/ /tmp/ansible/roles +ADD provision.yml /tmp/ansible/provision.yml -RUN mkdir /shed_tools && chown galaxy:galaxy /shed_tools +RUN mkdir /shed_tools && chown $GALAXY_USER:$GALAXY_USER /shed_tools # The following commands will be executed as User galaxy USER galaxy @@ -41,14 +64,10 @@ USER galaxy WORKDIR /galaxy-central # Configure Galaxy to use the Tool Shed -RUN cp /galaxy-central/config/galaxy.ini.sample /galaxy-central/config/galaxy.ini -RUN cp /galaxy-central/config/reports_wsgi.ini.sample /galaxy-central/config/reports_wsgi.ini -RUN mkdir /galaxy-central/tool_deps - -RUN virtualenv /home/galaxy/venv +RUN mkdir $GALAXY_ROOT/tool_deps # Fetching all Galaxy python dependencies -RUN . /home/galaxy/venv/bin/activate && python scripts/fetch_eggs.py && python scripts/fetch_eggs.py -e drmaa +RUN . $GALAXY_VIRTUALENV/bin/activate && python scripts/fetch_eggs.py && python scripts/fetch_eggs.py -e drmaa # Updating genome informations from UCSC #RUN export GALAXY=/galaxy-central && sh ./cron/updateucsc.sh.sample @@ -70,7 +89,7 @@ ENV GALAXY_CONFIG_FTP_UPLOAD_SITE galaxy.docker.org ENV GALAXY_CONFIG_USE_PBKDF2 False ENV GALAXY_CONFIG_NGINX_X_ACCEL_REDIRECT_BASE /_x_accel_redirect ENV GALAXY_CONFIG_NGINX_X_ARCHIVE_FILES_BASE /_x_accel_redirect -ENV GALAXY_CONFIG_NGINX_UPLOAD_STORE database/tmp/upload_store +ENV GALAXY_CONFIG_NGINX_UPLOAD_STORE /tmp/nginx_upload_store ENV GALAXY_CONFIG_NGINX_UPLOAD_PATH /_upload ENV GALAXY_CONFIG_DYNAMIC_PROXY_MANAGE False ENV GALAXY_CONFIG_VISUALIZATION_PLUGINS_DIRECTORY config/plugins/visualizations @@ -88,15 +107,6 @@ ENV PG_DATA_DIR_HOST /export/postgresql/9.3/main/ ADD ./servers.ini /galaxy-central/config/servers.ini RUN cat /galaxy-central/config/servers.ini >> /galaxy-central/config/galaxy.ini && rm /galaxy-central/config/servers.ini -ADD ./job_conf.xml /galaxy-central/config/job_conf.xml - -# can I remove this? -#RUN mkdir /galaxy-central/database/job_working_directory/ /galaxy-central/database/files/ - -# Add optional watchdog dependency to Galaxy's environment. -# We need the psutil library to configure SLURM at startup. It's not needed by Galaxy. -RUN . /home/galaxy/venv/bin/activate && pip install watchdog ipython pygments jinja2 psutil - # Install all required Node dependencies. This is required to get proxy support to work for Interactive Environments RUN cd /galaxy-central/lib/galaxy/web/proxy/js && npm install @@ -111,14 +121,6 @@ USER root ENV LC_ALL en_US.UTF-8 RUN locale-gen en_US.UTF-8 && dpkg-reconfigure locales -ADD ./nginx.conf /etc/nginx/nginx.conf -ADD ./supervisor.conf /etc/supervisor/conf.d/galaxy.conf - -ADD ./proftpd.conf /etc/proftpd/proftpd.conf -RUN echo 'LoadModule mod_sql.c' >> /etc/proftpd/modules.conf && \ - echo 'LoadModule mod_sql_passwd.c' >> /etc/proftpd/modules.conf && \ - echo 'LoadModule mod_sql_postgres.c' >> /etc/proftpd/modules.conf - # Include all needed scripts from the host ADD ./setup_postgresql.py /galaxy-central/setup_postgresql.py ADD ./create_galaxy_user.py /galaxy-central/create_galaxy_user.py @@ -135,9 +137,6 @@ RUN service postgresql start && sh create_db.sh RUN service postgresql start && sleep 5 && python create_galaxy_user.py --user admin@galaxy.org --password admin --key admin RUN service postgresql start && sudo -u galaxy -i -- sh -c "cd /galaxy-central/ && sh run.sh --daemon && sleep 60 && sh run.sh --stop-daemon" -# nginx and uwsgi Will be controller by supervisor -RUN update-rc.d -f uwsgi remove && update-rc.d -f nginx remove && update-rc.d -f proftpd remove - ADD ./startup.sh /usr/bin/startup # Script that enables easier downstream installation of tools (e.g. for different Galaxy Docker flavours) ADD install_repo_wrapper.sh /usr/bin/install-repository @@ -147,14 +146,6 @@ RUN chmod +x /usr/bin/install-repository /usr/bin/startup # (without running the startup.sh script) will crash because integrated_tool_panel.xml could not be found. ENV GALAXY_CONFIG_INTEGRATED_TOOL_PANEL_CONFIG /export/galaxy-central/integrated_tool_panel.xml -# Setup SLURM -# TODO use fixed key -RUN /usr/sbin/create-munge-key -RUN mkdir -p /var/run/munge && chown root:root /var/lib/munge/ /var/log/munge/ /var/run/munge /etc/munge/ /etc/munge/munge.key -ADD ./configure_slurm.py /usr/sbin/configure_slurm.py -# SLURM don't like world writeable StateSaveLocation folders -RUN mkdir /tmp/slurm && chown galaxy:galaxy /tmp/slurm - ADD ./cgroupfs_mount.sh /root/cgroupfs_mount.sh # Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9001 (Galaxy report app) @@ -163,8 +154,6 @@ EXPOSE :21 EXPOSE :8800 EXPOSE :9001 -RUN apt-get -qq update && apt-get install --no-install-recommends -y nano nmap lynx vim curl - RUN mkdir -p /galaxy-central/database/tmp/upload_store && chown galaxy:galaxy /galaxy-central/database/tmp/upload_store # We need to set $HOME for some Tool Shed tools (e.g Perl libs with $HOME/.cpan) ENV HOME /home/galaxy diff --git a/galaxy/configure_slurm.py b/galaxy/configure_slurm.py deleted file mode 100644 index 523090e4d..000000000 --- a/galaxy/configure_slurm.py +++ /dev/null @@ -1,96 +0,0 @@ -from socket import gethostname -from string import Template -from subprocess import call -from getpass import getuser -from os import environ -import psutil - -SLURM_CONFIG_TEMPLATE = ''' -# slurm.conf file generated by configurator.html. -# Put this file on all nodes of your cluster. -# See the slurm.conf man page for more information. -# -ControlMachine=$hostname -#ControlAddr= -#BackupController= -#BackupAddr= -# -AuthType=auth/munge -CacheGroups=0 -#CheckpointType=checkpoint/none -CryptoType=crypto/munge -MpiDefault=none -#PluginDir= -#PlugStackConfig= -#PrivateData=jobs -ProctrackType=proctrack/pgid -#Prolog= -#PrologSlurmctld= -#PropagatePrioProcess=0 -#PropagateResourceLimits= -#PropagateResourceLimitsExcept= -ReturnToService=1 -#SallocDefaultCommand= -SlurmctldPidFile=/var/run/slurmctld.pid -SlurmctldPort=6817 -SlurmdPidFile=/var/run/slurmd.pid -SlurmdPort=6818 -SlurmdSpoolDir=/tmp/slurmd -SlurmUser=$user -#SlurmdUser=root -#SrunEpilog= -#SrunProlog= -StateSaveLocation=/tmp/slurm -SwitchType=switch/none -#TaskEpilog= -TaskPlugin=task/none -#TaskPluginParam= -#TaskProlog= -InactiveLimit=0 -KillWait=30 -MinJobAge=300 -#OverTimeLimit=0 -SlurmctldTimeout=120 -SlurmdTimeout=300 -#UnkillableStepTimeout=60 -#VSizeFactor=0 -Waittime=0 -FastSchedule=1 -SchedulerType=sched/backfill -SchedulerPort=7321 -SelectType=select/cons_res -SelectTypeParameters=CR_Core_Memory -AccountingStorageType=accounting_storage/none -#AccountingStorageUser= -AccountingStoreJobComment=YES -ClusterName=cluster -#DebugFlags= -#JobCompHost= -#JobCompLoc= -#JobCompPass= -#JobCompPort= -JobCompType=jobcomp/none -#JobCompUser= -JobAcctGatherFrequency=30 -JobAcctGatherType=jobacct_gather/none -SlurmctldDebug=3 -#SlurmctldLogFile= -SlurmdDebug=3 -#SlurmdLogFile= -NodeName=$hostname CPUs=$cpus RealMemory=$memory State=UNKNOWN -PartitionName=debug Nodes=$hostname Default=YES MaxTime=INFINITE State=UP -''' - - -def main(): - template_params = { - "hostname": gethostname(), - "user": 'galaxy', - "cpus": environ.get("SLURM_CPUS", psutil.cpu_count()), - "memory": environ.get("SLURM_MEMORY", int(psutil.virtual_memory().total / (1024*1024))) - } - config_contents = Template(SLURM_CONFIG_TEMPLATE).substitute(template_params) - open("/etc/slurm-llnl/slurm.conf", "w").write(config_contents) - -if __name__ == "__main__": - main() diff --git a/galaxy/job_conf.xml b/galaxy/job_conf.xml deleted file mode 100644 index 51773cebc..000000000 --- a/galaxy/job_conf.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - /usr/lib/slurm-drmaa/lib/libdrmaa.so - - - - - - - - - - false - galaxy - - - - - \ No newline at end of file diff --git a/galaxy/proftpd.conf b/galaxy/proftpd.conf deleted file mode 100644 index acc75de12..000000000 --- a/galaxy/proftpd.conf +++ /dev/null @@ -1,63 +0,0 @@ -# Includes DSO modules -Include /etc/proftpd/modules.conf - - -# Basics, some site-specific -ServerName "Public Galaxy FTP" -ServerType standalone -DefaultServer on -Port 21 -Umask 000 -#SyslogFacility DAEMON -#SyslogLevel debug -MaxInstances 30 -User nobody -Group nogroup - -# Passive port range for the firewall -PassivePorts 30000 40000 - -# Cause every FTP user to be "jailed" (chrooted) into their home directory -DefaultRoot ~ - -# Automatically create home directory if it doesn't exist -CreateHome on dirmode 700 - -# Allow users to overwrite their files -AllowOverwrite on - -# Allow users to resume interrupted uploads -AllowStoreRestart on - -# Bar use of SITE CHMOD - - DenyAll - - -# Bar use of RETR (download) since this is not a public file drop - - DenyAll - - -# Do not authenticate against real (system) users -AuthPAM off - -# Set up mod_sql_password - Galaxy passwords are stored as hex-encoded SHA1 -SQLPasswordEngine on -SQLPasswordEncoding hex - -# Set up mod_sql to authenticate against the Galaxy database -SQLEngine on -SQLBackend postgres -SQLConnectInfo galaxy@localhost galaxy galaxy -SQLAuthTypes SHA1 -SQLAuthenticate users - -# An empty directory in case chroot fails -SQLDefaultHomedir /var/opt/local/proftpd - -# Define a custom query for lookup that returns a passwd-like entry. UID and GID should match your Galaxy user. -SQLUserInfo custom:/LookupGalaxyUser -SQLNamedQuery LookupGalaxyUser SELECT "email,password,'galaxy','galaxy','/export/galaxy-central/database/ftp/%U','/bin/bash' FROM galaxy_user WHERE email='%U'" - - diff --git a/galaxy/provision.yml b/galaxy/provision.yml new file mode 100644 index 000000000..a25473c98 --- /dev/null +++ b/galaxy/provision.yml @@ -0,0 +1,5 @@ +- hosts: localhost + connection: local + roles: + - role: galaxyprojectdotorg.galaxyextras + tags: galaxyextras diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras new file mode 160000 index 000000000..22a22099c --- /dev/null +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -0,0 +1 @@ +Subproject commit 22a22099cdbd4529a85b09845c37fc56b1e2671d diff --git a/galaxy/startup.sh b/galaxy/startup.sh index 7f63486fc..0f34ab290 100644 --- a/galaxy/startup.sh +++ b/galaxy/startup.sh @@ -8,7 +8,7 @@ umount /var/lib/docker python ./export_user_files.py $PG_DATA_DIR_DEFAULT # Configure SLURM with runtime hostname. -/home/galaxy/venv/bin/python /usr/sbin/configure_slurm.py +python /usr/sbin/configure_slurm.py # Try to guess if we are running under --privileged mode if mount | grep "/proc/kcore"; then diff --git a/galaxy/supervisor.conf b/galaxy/supervisor.conf deleted file mode 100644 index b0b06d656..000000000 --- a/galaxy/supervisor.conf +++ /dev/null @@ -1,100 +0,0 @@ -[supervisord] -nodaemon=false - -[program:munge] -user=root -command=/usr/sbin/munged -F -redirect_stderr=true - -[program:slurmctld] -user=root -command=/usr/sbin/slurmctld -D -L /home/galaxy/slurmctld.log -redirect_stderr=true - -[program:slurmd] -user=root -command=/usr/sbin/slurmd -D -L /home/galaxy/slurmd.log -redirect_stderr=true - -[program:postgresql] -user = postgres -command = /usr/lib/postgresql/9.3/bin/postmaster -D "/export/postgresql/9.3/main" -process_name = %(program_name)s -stopsignal = INT -autostart = true -autorestart = true -redirect_stderr = true - -[program:proftpd] -command = /usr/sbin/proftpd -n -c /etc/proftpd/proftpd.conf -autorestart = true -autorestart = true - -[program:nginx] -command = /usr/sbin/nginx -directory = / -umask = 022 -autostart = true -autorestart = unexpected -startsecs = 5 -exitcodes = 0 -user = root - -[program:galaxy_uwsgi] -command = /usr/bin/uwsgi --plugin python --ini-paste /galaxy-central/config/galaxy.ini -directory = /galaxy-central -umask = 022 -autostart = true -autorestart = true -startsecs = 10 -user = galaxy -environment = PATH=/home/galaxy/venv:/home/galaxy/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,PYTHON_EGG_CACHE=/home/galaxy/.python-eggs,PYTHONPATH=/galaxy-central/eggs/PasteDeploy-1.5.0-py2.7.egg -numprocs = 1 -stopsignal = INT - -[program:handler] -command = /home/galaxy/venv/bin/python ./scripts/paster.py serve config/galaxy.ini --server-name=handler%(process_num)s --pid-file=/home/galaxy/handler%(process_num)s.pid --log-file=/home/galaxy/handler%(process_num)s.log -directory = /galaxy-central -process_name = handler%(process_num)s -numprocs = 2 -umask = 022 -autostart = true -autorestart = true -startsecs = 15 -user = galaxy -environment = PYTHON_EGG_CACHE=/home/galaxy/.python-eggs - -[program:reports] -command = /home/galaxy/venv/bin/python ./scripts/paster.py serve config/reports_wsgi.ini --server-name=main --pid-file=/home/galaxy/reports.pid --log-file=/home/galaxy/reports.log -directory = /galaxy-central -process_name = reports -umask = 022 -autostart = false -autorestart = true -startsecs = 5 -user = galaxy -environment = PYTHON_EGG_CACHE=/home/galaxy/.python-eggs - -[program:galaxy_nodejs_proxy] -directory = /galaxy-central -command = /galaxy-central/lib/galaxy/web/proxy/js/lib/main.js --sessions database/session_map.sqlite --ip 0.0.0.0 --port 8800 -autostart = true -autorestart = unexpected -user = galaxy -startsecs = 5 -redirect_stderr = true - - -[program:docker] -directory = / -command = /usr/bin/docker -d -autostart = false -autorestart = true -user = root -startsecs = 5 -redirect_stderr = true - -[group:galaxy] -programs = handler, galaxy_uwsgi, galaxy_nodejs_proxy - - From 88d96fe1cddaa5b9e73ad5bb1c65e0373b5c2b38 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 30 Jan 2015 22:43:48 +0100 Subject: [PATCH 06/71] use default branch and track latest changes --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index cd280c32c..10cb3fb55 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -29,7 +29,7 @@ RUN groupadd -r galaxy -g 450 && \ # Download latest stable release of Galaxy. -ENV GALAXY_RELEASE latest_2015.01.13 +ENV GALAXY_RELEASE dev ENV GALAXY_ROOT /galaxy-central/ RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R galaxy:galaxy $GALAXY_ROOT From 03d88f8945f0d4bfa638642d877404eed69502ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Fri, 30 Jan 2015 22:47:56 +0100 Subject: [PATCH 07/71] Track `default` branch of galaxy-central. --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index cd280c32c..e5c4991b8 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -29,7 +29,7 @@ RUN groupadd -r galaxy -g 450 && \ # Download latest stable release of Galaxy. -ENV GALAXY_RELEASE latest_2015.01.13 +ENV GALAXY_RELEASE default ENV GALAXY_ROOT /galaxy-central/ RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R galaxy:galaxy $GALAXY_ROOT From 770d946d2d986f4a82501c56b537b0a859acbf73 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 30 Jan 2015 23:57:52 +0100 Subject: [PATCH 08/71] use apt-add-repository --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 1f3075732..d8eee1cba 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" && \ apt-get update -qq && apt-get upgrade -y && \ apt-add-repository -y ppa:ansible/ansible && \ - add-apt-repository ppa:galaxyproject/nginx && \ + apt-add-repository -y ppa:galaxyproject/nginx && \ apt-get -qq update && \ apt-get purge -y software-properties-common && \ apt-get install --no-install-recommends -y mercurial python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv wget \ From b1b3100f2148843dccd01316dc1714e68e4518a9 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 31 Jan 2015 00:10:45 +0100 Subject: [PATCH 09/71] Add job_metrics_conf.xml file with standard plugins enabled. --- galaxy/job_metrics_conf.xml | 124 ++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 galaxy/job_metrics_conf.xml diff --git a/galaxy/job_metrics_conf.xml b/galaxy/job_metrics_conf.xml new file mode 100644 index 000000000..2d1e63784 --- /dev/null +++ b/galaxy/job_metrics_conf.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3866bab18154cbf59cf7ee0ab657ffa61fa42e10 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 31 Jan 2015 00:11:07 +0100 Subject: [PATCH 10/71] add job_metrics file to Dockerfile --- galaxy/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index d8eee1cba..9cc94ab2a 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -48,6 +48,7 @@ RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" # Setup Galaxy configuration files. RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_DIR/galaxy.ini && \ cp $GALAXY_ROOT/config/reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" +ADD job_metrics_conf.xml $GALAXY_CONFIG_DIR/job_metrics_conf.xml ADD roles/ /tmp/ansible/roles ADD provision.yml /tmp/ansible/provision.yml RUN ansible-playbook /tmp/ansible/provision.yml --extra-vars galaxy_user_name=$GALAXY_USER --extra-vars galaxy_config_file=$GALAXY_CONFIG_DIR/galaxy.ini --tags=galaxyextras -c local && \ From a55ed817b8571be46cc56c57460514d2b1705943 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 31 Jan 2015 00:12:13 +0100 Subject: [PATCH 11/71] enable new toolform --- galaxy/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 9cc94ab2a..c99e2bc17 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -95,6 +95,7 @@ ENV GALAXY_CONFIG_NGINX_UPLOAD_PATH /_upload ENV GALAXY_CONFIG_DYNAMIC_PROXY_MANAGE False ENV GALAXY_CONFIG_VISUALIZATION_PLUGINS_DIRECTORY config/plugins/visualizations ENV GALAXY_CONFIG_TRUST_IPYTHON_NOTEBOOK_CONVERSION True +ENV GALAXY_CONFIG_TOOLFORM_UPGRADE True # Next line allow child docker container for viz to find this docker container. ENV GALAXY_CONFIG_GALAXY_INFRASTRUCTURE_URL http://$HOST_IP/ ENV GALAXY_CONFIG_SANITIZE_ALL_HTML False From b9a68944c7021ab75143282e8080a8cf3e999e2e Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 31 Jan 2015 00:16:49 +0100 Subject: [PATCH 12/71] Disable env JobMetric. --- galaxy/job_metrics_conf.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/job_metrics_conf.xml b/galaxy/job_metrics_conf.xml index 2d1e63784..522e6e8d5 100644 --- a/galaxy/job_metrics_conf.xml +++ b/galaxy/job_metrics_conf.xml @@ -32,7 +32,7 @@ - + From 5221813b020aa6b051ea483860c932da8cf04db2 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 30 Jan 2015 22:06:33 -0500 Subject: [PATCH 13/71] Update for pointing uploads at /tmp. --- galaxy/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index c99e2bc17..aa0b519eb 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -156,7 +156,6 @@ EXPOSE :21 EXPOSE :8800 EXPOSE :9001 -RUN mkdir -p /galaxy-central/database/tmp/upload_store && chown galaxy:galaxy /galaxy-central/database/tmp/upload_store # We need to set $HOME for some Tool Shed tools (e.g Perl libs with $HOME/.cpan) ENV HOME /home/galaxy From 8879345d3419c57762f41528419195fc1f23ff66 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 30 Jan 2015 22:06:56 -0500 Subject: [PATCH 14/71] Move stuff outside of /galaxy-central. In particular the following two files are no longer setup inside of /galaxy-central. - /galaxy-central/config/galaxy.ini has become /etc/galaxy/galaxy.ini - /galaxy-central/config/galaxy.ini has become /etc/galaxy/report_wsgi.ini This second change requires the modifications found in https://bitbucket.org/galaxy/galaxy-central/commits/57217275bebe445be7bdae43b9072bcca47ff3e7 - and so should not be merged into master until March 2015 release of Galaxy. --- galaxy/Dockerfile | 22 ++++++++++--------- galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index aa0b519eb..fe1a35c6c 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -28,8 +28,8 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo # Download latest stable release of Galaxy. ENV GALAXY_RELEASE default ENV GALAXY_ROOT /galaxy-central -# TODO: make this /etc/galaxy -ENV GALAXY_CONFIG_DIR /galaxy-central/config +ENV GALAXY_CONFIG_DIR /etc/galaxy +ENV GALAXY_CONFIG_FILE $GALAXY_CONFIG_DIR/galaxy.ini ENV GALAXY_VIRTUALENV /home/galaxy/venv ENV GALAXY_USER galaxy ENV GALAXY_HOME /home/galaxy @@ -46,12 +46,16 @@ RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-centr RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" # Setup Galaxy configuration files. -RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_DIR/galaxy.ini && \ +RUN mkdir -p $GALAXY_CONFIG_DIR && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CONFIG_DIR + +RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE && \ cp $GALAXY_ROOT/config/reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" ADD job_metrics_conf.xml $GALAXY_CONFIG_DIR/job_metrics_conf.xml +ADD ./servers.ini $GALAXY_CONFIG_DIR/servers.ini +RUN cat $GALAXY_CONFIG_DIR/servers.ini >> $GALAXY_CONFIG_FILE && rm $GALAXY_CONFIG_DIR/servers.ini ADD roles/ /tmp/ansible/roles ADD provision.yml /tmp/ansible/provision.yml -RUN ansible-playbook /tmp/ansible/provision.yml --extra-vars galaxy_user_name=$GALAXY_USER --extra-vars galaxy_config_file=$GALAXY_CONFIG_DIR/galaxy.ini --tags=galaxyextras -c local && \ +RUN ansible-playbook /tmp/ansible/provision.yml --extra-vars galaxy_user_name=$GALAXY_USER --extra-vars galaxy_config_file=$GALAXY_CONFIG_FILE --extra-vars galaxy_config_dir=$GALAXY_CONFIG_DIR --tags=galaxyextras -c local && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ADD roles/ /tmp/ansible/roles @@ -68,7 +72,7 @@ WORKDIR /galaxy-central RUN mkdir $GALAXY_ROOT/tool_deps # Fetching all Galaxy python dependencies -RUN . $GALAXY_VIRTUALENV/bin/activate && python scripts/fetch_eggs.py && python scripts/fetch_eggs.py -e drmaa +RUN . $GALAXY_VIRTUALENV/bin/activate && python scripts/fetch_eggs.py -c $GALAXY_CONFIG_FILE && python scripts/fetch_eggs.py -e drmaa -c $GALAXY_CONFIG_FILE # Updating genome informations from UCSC #RUN export GALAXY=/galaxy-central && sh ./cron/updateucsc.sh.sample @@ -106,8 +110,6 @@ ENV GALAXY_CONFIG_OVERRIDE_DEBUG False ENV PG_DATA_DIR_DEFAULT /var/lib/postgresql/9.3/main/ ENV PG_DATA_DIR_HOST /export/postgresql/9.3/main/ -ADD ./servers.ini /galaxy-central/config/servers.ini -RUN cat /galaxy-central/config/servers.ini >> /galaxy-central/config/galaxy.ini && rm /galaxy-central/config/servers.ini # Install all required Node dependencies. This is required to get proxy support to work for Interactive Environments RUN cd /galaxy-central/lib/galaxy/web/proxy/js && npm install @@ -125,7 +127,6 @@ RUN locale-gen en_US.UTF-8 && dpkg-reconfigure locales # Include all needed scripts from the host ADD ./setup_postgresql.py /galaxy-central/setup_postgresql.py -ADD ./create_galaxy_user.py /galaxy-central/create_galaxy_user.py ADD ./export_user_files.py /galaxy-central/export_user_files.py # Configure PostgreSQL @@ -135,8 +136,9 @@ ADD ./export_user_files.py /galaxy-central/export_user_files.py RUN service postgresql stop RUN rm $PG_DATA_DIR_DEFAULT -rf RUN python setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT -RUN service postgresql start && sh create_db.sh -RUN service postgresql start && sleep 5 && python create_galaxy_user.py --user admin@galaxy.org --password admin --key admin +RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE +ADD ./create_galaxy_user.py /galaxy-central/create_galaxy_user.py +RUN service postgresql start && sleep 5 && python create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin RUN service postgresql start && sudo -u galaxy -i -- sh -c "cd /galaxy-central/ && sh run.sh --daemon && sleep 60 && sh run.sh --stop-daemon" ADD ./startup.sh /usr/bin/startup diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index 22a22099c..d0cdefdba 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit 22a22099cdbd4529a85b09845c37fc56b1e2671d +Subproject commit d0cdefdba405be72b57748738d6ce09129e2c311 From a90d3f346be38c691e2a20e0838271b9d5d0d6f9 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 30 Jan 2015 22:32:29 -0500 Subject: [PATCH 15/71] Replace uid/gid in export_user_files.py with constants... ... for readability. --- galaxy/export_user_files.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index 4b79ce490..5e217bb7e 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -10,6 +10,9 @@ PG_DATA_DIR_HOST = os.environ.get("PG_DATA_DIR_HOST", "/export/postgresql/9.3/main/") PG_CONF = '/etc/postgresql/9.3/main/postgresql.conf' +GALAXY_UID = 451 +GALAXY_GID = 450 + def change_path( src ): """ @@ -24,8 +27,8 @@ def change_path( src ): os.makedirs(dest_dir) shutil.move( src, dest ) os.symlink( dest, src.rstrip('/') ) - os.chown( src, 451, 450 ) - subprocess.call('chown -R 451:450 %s' % dest, shell=True) + os.chown( src, GALAXY_UID, GALAXY_GID ) + subprocess.call('chown -R %d:%d %s' % (GALAXY_UID, GALAXY_GID, dest), shell=True) # if destination exists (e.g. continuing a previous session), remove source and symlink else: if os.path.isdir( src ): @@ -48,7 +51,7 @@ def change_path( src ): shutil.copytree( '/galaxy-central/config/', '/export/.distribution_config/' ) if not os.path.exists( '/export/galaxy-central/' ): os.makedirs("/export/galaxy-central/") - os.chown("/export/galaxy-central/", 451, 450) + os.chown( "/export/galaxy-central/", GALAXY_UID, GALAXY_GID ) change_path('/galaxy-central/config/') change_path('/galaxy-central/static/welcome.html') change_path('/galaxy-central/integrated_tool_panel.xml') From 911c2fb5d9446ca016ec30f20c4dc15df282293d Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 30 Jan 2015 23:36:50 -0500 Subject: [PATCH 16/71] Small tweaks to job related configuration handling. - Move job_metrics_conf.xml configuration out into ansible so it can be reused outside the context of Docker (https://github.com/galaxyproject/ansible-galaxy-extras/commit/97915bc7e791d3755c140fb1802e56800ae27da9). - Move job metrics config file into /etc/galaxy (see https://github.com/bgruening/docker-galaxy-stable/issues/31). - Move job config file into /etc/galaxy (see https://github.com/bgruening/docker-galaxy-stable/issues/31). --- galaxy/Dockerfile | 11 +- galaxy/job_metrics_conf.xml | 124 ------------------ galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 3 files changed, 10 insertions(+), 127 deletions(-) delete mode 100644 galaxy/job_metrics_conf.xml diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index fe1a35c6c..b3ea10eb9 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -30,6 +30,8 @@ ENV GALAXY_RELEASE default ENV GALAXY_ROOT /galaxy-central ENV GALAXY_CONFIG_DIR /etc/galaxy ENV GALAXY_CONFIG_FILE $GALAXY_CONFIG_DIR/galaxy.ini +ENV GALAXY_CONFIG_JOB_CONFIG_FILE $GALAXY_CONFIG_DIR/job_conf.xml +ENV GALAXY_CONFIG_JOB_METRICS_CONFIG_FILE $GALAXY_CONFIG_DIR/job_metrics_conf.xml ENV GALAXY_VIRTUALENV /home/galaxy/venv ENV GALAXY_USER galaxy ENV GALAXY_HOME /home/galaxy @@ -50,12 +52,17 @@ RUN mkdir -p $GALAXY_CONFIG_DIR && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CO RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE && \ cp $GALAXY_ROOT/config/reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" -ADD job_metrics_conf.xml $GALAXY_CONFIG_DIR/job_metrics_conf.xml ADD ./servers.ini $GALAXY_CONFIG_DIR/servers.ini RUN cat $GALAXY_CONFIG_DIR/servers.ini >> $GALAXY_CONFIG_FILE && rm $GALAXY_CONFIG_DIR/servers.ini ADD roles/ /tmp/ansible/roles ADD provision.yml /tmp/ansible/provision.yml -RUN ansible-playbook /tmp/ansible/provision.yml --extra-vars galaxy_user_name=$GALAXY_USER --extra-vars galaxy_config_file=$GALAXY_CONFIG_FILE --extra-vars galaxy_config_dir=$GALAXY_CONFIG_DIR --tags=galaxyextras -c local && \ +RUN ansible-playbook /tmp/ansible/provision.yml \ + --extra-vars galaxy_user_name=$GALAXY_USER \ + --extra-vars galaxy_config_file=$GALAXY_CONFIG_FILE \ + --extra-vars galaxy_config_dir=$GALAXY_CONFIG_DIR \ + --extra-vars galaxy_job_conf_path=$GALAXY_CONFIG_JOB_CONFIG_FILE \ + --extra-vars galaxy_job_metrics_conf_path=$GALAXY_CONFIG_JOB_METRICS_CONFIG_FILE \ + --tags=galaxyextras -c local && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ADD roles/ /tmp/ansible/roles diff --git a/galaxy/job_metrics_conf.xml b/galaxy/job_metrics_conf.xml deleted file mode 100644 index 522e6e8d5..000000000 --- a/galaxy/job_metrics_conf.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index d0cdefdba..97915bc7e 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit d0cdefdba405be72b57748738d6ce09129e2c311 +Subproject commit 97915bc7e791d3755c140fb1802e56800ae27da9 From 14737e639e8b985996939eb1f944d02d4901e428 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 30 Jan 2015 23:42:45 -0500 Subject: [PATCH 17/71] Small tweaks to README. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bcdf25a77..31d6136e5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ One of the main goals is to make the access to entire tool suites as easy as pos this includes the setup of a public available webservice that needs to be maintained, or that the Tool-user needs to either setup a Galaxy Server by its own or to have Admin access to a local Galaxy server. With docker, tool developers can create their own Image with all dependencies and the user only needs to run it within docker. -The Image is based on [Debian/wheezy](http://www.debian.org/). and all recommended Galaxy requirements are installed. +The Image is based on [Ubuntu 14.04 LTS](http://releases.ubuntu.com/14.04/) and all recommended Galaxy requirements are installed. Usage @@ -74,7 +74,7 @@ If you want to restart Galaxy without restarting the entire Galaxy container we ```docker exec supervisorctl restart galaxy:``` -Advanced logging +Advanced Logging ---------------- You can set the environment variable $GALAXY_LOGGING to FULL to access all logs from supervisor. For example start your container with: @@ -82,7 +82,7 @@ You can set the environment variable $GALAXY_LOGGING to FULL to access all logs ``docker run -d -p 8080:80 -p 8021:21 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable`` -Extending the docker Image +Extending the Docker Image ========================== If you have your Tools already included in the Tool Shed, building your own personalised Galaxy docker Image can be done using the following steps: From a1e74b24d3437922757280d62b48838c8639bc92 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 30 Jan 2015 23:45:52 -0500 Subject: [PATCH 18/71] Export port 9002 (supervisor web app). Free GUI for managing processes - allows restarting Galaxy, start reports, etc... --- galaxy/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index b3ea10eb9..e73b56a48 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -159,11 +159,12 @@ ENV GALAXY_CONFIG_INTEGRATED_TOOL_PANEL_CONFIG /export/galaxy-central/integrated ADD ./cgroupfs_mount.sh /root/cgroupfs_mount.sh -# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9001 (Galaxy report app) +# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9001 (Galaxy report app), 9002 (supvisord web app) EXPOSE :80 EXPOSE :21 EXPOSE :8800 EXPOSE :9001 +EXPOSE :9002 # We need to set $HOME for some Tool Shed tools (e.g Perl libs with $HOME/.cpan) ENV HOME /home/galaxy From 7341e977b1b838367127af941331ce0a4256784b Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 31 Jan 2015 23:55:43 +0100 Subject: [PATCH 19/71] Put UID and GID into environment variables. --- galaxy/Dockerfile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index c99e2bc17..1f2a7ac46 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -32,11 +32,13 @@ ENV GALAXY_ROOT /galaxy-central ENV GALAXY_CONFIG_DIR /galaxy-central/config ENV GALAXY_VIRTUALENV /home/galaxy/venv ENV GALAXY_USER galaxy +ENV GALAXY_UID 1450 +ENV GALAXY_GID 1450 ENV GALAXY_HOME /home/galaxy ENV EXPORT_DIR /export -RUN groupadd -r $GALAXY_USER -g 450 && \ - useradd -u 451 -r -g $GALAXY_USER -d $GALAXY_HOME -c "Galaxy user" $GALAXY_USER && \ +RUN groupadd -r $GALAXY_USER -g $GALAXY_GID && \ + useradd -u $GALAXY_UID -r -g $GALAXY_USER -d $GALAXY_HOME -c "Galaxy user" $GALAXY_USER && \ mkdir $EXPORT_DIR $GALAXY_HOME && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_HOME $EXPORT_DIR && \ gpasswd -a $GALAXY_USER docker @@ -51,6 +53,7 @@ RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_ ADD job_metrics_conf.xml $GALAXY_CONFIG_DIR/job_metrics_conf.xml ADD roles/ /tmp/ansible/roles ADD provision.yml /tmp/ansible/provision.yml + RUN ansible-playbook /tmp/ansible/provision.yml --extra-vars galaxy_user_name=$GALAXY_USER --extra-vars galaxy_config_file=$GALAXY_CONFIG_DIR/galaxy.ini --tags=galaxyextras -c local && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* From d009a4cac204f449cf84f726c140498feb9c849f Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 31 Jan 2015 23:56:27 +0100 Subject: [PATCH 20/71] Use environment variables instead of hard-coded uid and gid. --- galaxy/export_user_files.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index 4b79ce490..fed9644b1 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -24,8 +24,8 @@ def change_path( src ): os.makedirs(dest_dir) shutil.move( src, dest ) os.symlink( dest, src.rstrip('/') ) - os.chown( src, 451, 450 ) - subprocess.call('chown -R 451:450 %s' % dest, shell=True) + os.chown( src, int(os.environ['GALAXY_UID']), int(os.environ['GALAXY_GID']) ) + subprocess.call( 'chown -R %s:%s %s' % ( os.environ['GALAXY_UID'], os.environ['GALAXY_GID'], dest ), shell=True ) # if destination exists (e.g. continuing a previous session), remove source and symlink else: if os.path.isdir( src ): @@ -48,7 +48,7 @@ def change_path( src ): shutil.copytree( '/galaxy-central/config/', '/export/.distribution_config/' ) if not os.path.exists( '/export/galaxy-central/' ): os.makedirs("/export/galaxy-central/") - os.chown("/export/galaxy-central/", 451, 450) + os.chown( "/export/galaxy-central/", int(os.environ['GALAXY_UID']), int(os.environ['GALAXY_GID']) ) change_path('/galaxy-central/config/') change_path('/galaxy-central/static/welcome.html') change_path('/galaxy-central/integrated_tool_panel.xml') From bcfbd0d28a774b6f2e4508e4a8517f9ee5019e10 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 00:13:05 +0100 Subject: [PATCH 21/71] update readme file --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 31d6136e5..cd3d498c6 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,20 @@ The proftpd server is configured to use the main galaxy PostgreSQL user to acces docker container in production, please do not forget to change the user credentials in /etc/proftp/proftpd.conf too. +Development +=========== + +This repository uses a git submodule to include Ansible roles maintained by the Galaxy project. + +https://github.com/galaxyproject/ansible-galaxy-extras + +You can clone this repository and the Ansible submodule with: + +``` +git clone --recursive https://github.com/bgruening/docker-galaxy-stable.git +``` + + Requirements ============ From 64e4c181dd91e0959f4e97032a513fbca8506799 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 02:55:35 +0100 Subject: [PATCH 22/71] Serve the Galaxy report webapp on port 9003 --- galaxy/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 67f00e92f..d803a5cd7 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -161,12 +161,12 @@ ENV GALAXY_CONFIG_INTEGRATED_TOOL_PANEL_CONFIG /export/galaxy-central/integrated ADD ./cgroupfs_mount.sh /root/cgroupfs_mount.sh -# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9001 (Galaxy report app), 9002 (supvisord web app) +# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9003 (Galaxy report app), 9002 (supvisord web app) EXPOSE :80 EXPOSE :21 EXPOSE :8800 -EXPOSE :9001 EXPOSE :9002 +EXPOSE :9003 # We need to set $HOME for some Tool Shed tools (e.g Perl libs with $HOME/.cpan) ENV HOME /home/galaxy From e04f5e3f8ab8501c9be1947bd3ee32bfa493b8ba Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 03:00:43 +0100 Subject: [PATCH 23/71] update readme file to reflect recent changes by John --- README.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cd3d498c6..d2647ff5b 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ environmental variable DOCKER_PARENT ``docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true -e DOCKER_PARENT=True -v /var/run/docker.sock:/var/run/docker.sock -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` -Enabling the Galaxy Report Tool -------------------------------- +Enabling the Galaxy Report Webapp +--------------------------------- -For admins wishing to have more information on the status of a galaxy instance, you can start this image with ``-p 9001:9001`` to serve the Galaxy Report Tool -on port 9001 on your host system. +For admins wishing to have more information on the status of a galaxy instance, you can start this image with ``-p 9003:9003`` to serve the Galaxy Report Webapp +on port 9003 on your host system. -``docker run -d -p 8080:80 -p 8021:21 -p 9001:9001 -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` +``docker run -d -p 8080:80 -p 8021:21 -p 9003:9003 -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` Restarting Galaxy @@ -73,6 +73,10 @@ If you want to restart Galaxy without restarting the entire Galaxy container we ```docker exec supervisorctl restart galaxy:``` +In addition you start/stop every supersisord process using a webinterface on port `9002`. Start your container with: + +``docker run -p 9002:9002 bgruening/galaxy-stable`` + Advanced Logging ---------------- @@ -81,6 +85,10 @@ You can set the environment variable $GALAXY_LOGGING to FULL to access all logs ``docker run -d -p 8080:80 -p 8021:21 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable`` +In addition you can access the supersisord webinterface on port 9002 and get access to log files. Start your container with: + +``docker run -d -p 8080:80 -p 8021:21 -p 9002:9002 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable`` + Extending the Docker Image ========================== @@ -164,6 +172,11 @@ History - 0.3: Add Interactive Environments - IPython in docker in Galaxy in docker - advanged logging + - 0.4: + - base the image on toolshed/requirements with all required Galaxy dependencies + - use Ansible roles to build large parts of the image + - export the supervisord webinterface on port 9002 + - enable Galaxy reports webapp Support & Bug Reports From ed58bf20f74a21cc5d14383f502876374d7c4a69 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 31 Jan 2015 22:26:59 -0500 Subject: [PATCH 24/71] Do not write helper scripts to /galaxy-central. Write them to /usr/bin/local instead. --- galaxy/Dockerfile | 10 +++++----- galaxy/create_galaxy_user.py | 4 ++++ galaxy/startup.sh | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index d803a5cd7..e6cdc29fe 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -135,8 +135,8 @@ ENV LC_ALL en_US.UTF-8 RUN locale-gen en_US.UTF-8 && dpkg-reconfigure locales # Include all needed scripts from the host -ADD ./setup_postgresql.py /galaxy-central/setup_postgresql.py -ADD ./export_user_files.py /galaxy-central/export_user_files.py +ADD ./setup_postgresql.py /usr/local/bin/setup_postgresql.py +ADD ./export_user_files.py /usr/local/bin/export_user_files.py # Configure PostgreSQL # 1. Remove all old configuration @@ -144,10 +144,10 @@ ADD ./export_user_files.py /galaxy-central/export_user_files.py # 3. Create Galaxy Admin User 'admin@galaxy.org' with password 'admin' and API key 'admin' RUN service postgresql stop RUN rm $PG_DATA_DIR_DEFAULT -rf -RUN python setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT +RUN python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE -ADD ./create_galaxy_user.py /galaxy-central/create_galaxy_user.py -RUN service postgresql start && sleep 5 && python create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin +ADD ./create_galaxy_user.py /usr/local/bin/create_galaxy_user.py +RUN service postgresql start && sleep 5 && python /usr/local/bin/create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin RUN service postgresql start && sudo -u galaxy -i -- sh -c "cd /galaxy-central/ && sh run.sh --daemon && sleep 60 && sh run.sh --stop-daemon" ADD ./startup.sh /usr/bin/startup diff --git a/galaxy/create_galaxy_user.py b/galaxy/create_galaxy_user.py index f62a50c65..aac27f451 100644 --- a/galaxy/create_galaxy_user.py +++ b/galaxy/create_galaxy_user.py @@ -1,3 +1,7 @@ +import sys +sys.path.insert(1,'/galaxy-central') +sys.path.insert(1,'/galaxy-central/lib') + from scripts.db_shell import * from galaxy.util.bunch import Bunch from galaxy.security import GalaxyRBACAgent diff --git a/galaxy/startup.sh b/galaxy/startup.sh index 0f34ab290..cb868dc12 100644 --- a/galaxy/startup.sh +++ b/galaxy/startup.sh @@ -5,7 +5,7 @@ cd /galaxy-central/ # symlinks will point from the original location to the new path under /export/ # If /export/ is not given, nothing will happen in that step umount /var/lib/docker -python ./export_user_files.py $PG_DATA_DIR_DEFAULT +python /usr/local/bin/export_user_files.py $PG_DATA_DIR_DEFAULT # Configure SLURM with runtime hostname. python /usr/sbin/configure_slurm.py From de91b94754249979db0337b165db65d8a74f6fdc Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 31 Jan 2015 22:27:53 -0500 Subject: [PATCH 25/71] Remove redundant line from Dockerfile. I assume this was done to fetch eggs originally - this is done by ansible now as part of running /galaxy-central/scripts/common_startup.sh. --- galaxy/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index e6cdc29fe..c09de49bb 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -148,7 +148,6 @@ RUN python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galax RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE ADD ./create_galaxy_user.py /usr/local/bin/create_galaxy_user.py RUN service postgresql start && sleep 5 && python /usr/local/bin/create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin -RUN service postgresql start && sudo -u galaxy -i -- sh -c "cd /galaxy-central/ && sh run.sh --daemon && sleep 60 && sh run.sh --stop-daemon" ADD ./startup.sh /usr/bin/startup # Script that enables easier downstream installation of tools (e.g. for different Galaxy Docker flavours) From c09412b00adbb694ef1666007b9b351f139a5ec3 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Sat, 31 Jan 2015 22:28:51 -0500 Subject: [PATCH 26/71] Drop nginx.conf - now this is handled by ansible. --- galaxy/nginx.conf | 110 ---------------------------------------------- 1 file changed, 110 deletions(-) delete mode 100644 galaxy/nginx.conf diff --git a/galaxy/nginx.conf b/galaxy/nginx.conf deleted file mode 100644 index 902899e5f..000000000 --- a/galaxy/nginx.conf +++ /dev/null @@ -1,110 +0,0 @@ -user galaxy; -worker_processes 1; -daemon off; - -events { - worker_connections 1024; -} - -http { - include mime.types; - default_type application/octet-stream; - - sendfile on; - - keepalive_timeout 65; - types_hash_max_size 2048; - - gzip on; - gzip_vary on; - gzip_proxied any; - gzip_comp_level 6; - gzip_buffers 16 8k; - gzip_http_version 1.1; - gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; - - client_max_body_size 50g; - uwsgi_read_timeout 300; - - #server { - # listen 9000; - - # location / { - # uwsgi_pass 127.0.0.1:9001; - # include uwsgi_params; - # } - #} - - server { - listen 80 default_server; - server_name localhost; - - # pass to uWSGI by default - location / { - uwsgi_pass 127.0.0.1:4001; - include uwsgi_params; - } - - # serve static content - location /static { - alias /galaxy-central/static; - gzip on; - gzip_types text/plain text/xml text/javascript text/css application/x-javascript; - expires 24h; - } - location /static/style { - alias /galaxy-central/static/style/blue; - gzip on; - gzip_types text/plain text/xml text/javascript text/css application/x-javascript; - expires 24h; - } - location /static/scripts { - alias /galaxy-central/static/scripts/packed; - gzip on; - gzip_types text/plain text/javascript application/x-javascript; - expires 24h; - } - - # delegated downloads - location /_x_accel_redirect { - internal; - alias /; - } - - location ~ ^/plugins/visualizations/ipython/static/(?.*?)$ { - alias /galaxy-central/config/plugins/interactive_environments/ipython/static/$static_file; - } - location ~ ^/plugins/visualizations/(?.+?)/static/(?.*?)$ { - alias /galaxy-central/config/plugins/visualizations/$vis_name/static/$static_file; - } - - - # delegated uploads - location /_upload { - upload_store /galaxy-central/database/tmp/upload_store; - upload_store_access user:rw; - upload_pass_form_field ""; - upload_set_form_field "__${upload_field_name}__is_composite" "true"; - upload_set_form_field "__${upload_field_name}__keys" "name path"; - upload_set_form_field "${upload_field_name}_name" "$upload_file_name"; - upload_set_form_field "${upload_field_name}_path" "$upload_tmp_path"; - upload_pass_args on; - upload_pass /_upload_done; - } - location /_upload_done { - set $dst /api/tools; - if ($args ~ nginx_redir=([^&]+)) { - set $dst $1; - } - rewrite "" $dst; - } - - error_page 502 /502.html; - location = /502.html { - root /root/; - proxy_intercept_errors on; - } - - - } -} From e0fe628ec4ff9399241836882e94e0ba0c690462 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 13:29:13 +0100 Subject: [PATCH 27/71] Update install-repository script. Allow for multiple installations in one run. Be smarter at determining if Galaxy is running. --- galaxy/install_repo_wrapper.sh | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/galaxy/install_repo_wrapper.sh b/galaxy/install_repo_wrapper.sh index 0868f87f3..5db48de17 100644 --- a/galaxy/install_repo_wrapper.sh +++ b/galaxy/install_repo_wrapper.sh @@ -1,11 +1,35 @@ #!/bin/sh # start Galaxy -/etc/init.d/postgresql start -./run.sh --daemon -sleep 60 +service postgresql start +install_log='galaxy_install.log' +./run.sh --daemon --log-file=$install_log --pid-file=galaxy_install.pid + +galaxy_install_pid=`cat galaxy_install.pid` + +while : ; do + tail -n 2 $install_log | grep -q "Removing PID file galaxy_install.pid" + if [ $? -eq 0 ] ; then + echo "Galaxy could not be started." + echo "More information about this failure may be found in the following log snippet from galaxy_install.log:" + echo "========================================" + tail -n 60 $install_log + echo "========================================" + echo $1 + exit 1 + fi + tail -n 2 $install_log | grep -q "Starting server in PID $galaxy_install_pid" + if [ $? -eq 0 ] ; then + echo "Galaxy is running." + break + fi +done + +for repository in "$@"; do + echo "Processing:\t $repository" + python ./scripts/api/install_tool_shed_repositories.py --api admin -l http://localhost:8080 --tool-deps --repository-deps $repository +done -python ./scripts/api/install_tool_shed_repositories.py --api admin -l http://localhost:8080 --tool-deps --repository-deps $1 exit_code=$? if [ $exit_code != 0 ] ; then @@ -14,4 +38,5 @@ fi # stop everything ./run.sh --stop-daemon +rm $install_log service postgresql stop From 7a68920feb5f11478045dae7b23a9e00aba4415b Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 17:27:05 +0100 Subject: [PATCH 28/71] fix comment --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index c09de49bb..3a02ff7fe 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -25,7 +25,6 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo nano nmap lynx vim curl python-pip && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -# Download latest stable release of Galaxy. ENV GALAXY_RELEASE default ENV GALAXY_ROOT /galaxy-central ENV GALAXY_CONFIG_DIR /etc/galaxy @@ -44,6 +43,7 @@ RUN groupadd -r $GALAXY_USER -g $GALAXY_GID && \ mkdir $EXPORT_DIR $GALAXY_HOME && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_HOME $EXPORT_DIR && \ gpasswd -a $GALAXY_USER docker +# Download latest stable release of Galaxy. RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_ROOT # TODO: ensure virtualenv as part of galaxy role From ee8d42e65b3cf4c336284dd247831f54c075e4f6 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 17:28:08 +0100 Subject: [PATCH 29/71] Run Galaxy as galaxy user. Certain ./configure scripts are not allowed to be run as root. --- galaxy/install_repo_wrapper.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/install_repo_wrapper.sh b/galaxy/install_repo_wrapper.sh index 5db48de17..8dcecd33c 100644 --- a/galaxy/install_repo_wrapper.sh +++ b/galaxy/install_repo_wrapper.sh @@ -3,7 +3,7 @@ # start Galaxy service postgresql start install_log='galaxy_install.log' -./run.sh --daemon --log-file=$install_log --pid-file=galaxy_install.pid +sudo -E -u galaxy ./run.sh --daemon --log-file=$install_log --pid-file=galaxy_install.pid galaxy_install_pid=`cat galaxy_install.pid` From 60aa9d4e9fa2c3e86b62f721625d55f580bf8b43 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 17:43:12 +0100 Subject: [PATCH 30/71] style fix --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 3a02ff7fe..a80d0b318 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -11,7 +11,7 @@ MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com # * Enable the @natefoo magic # Web server infrastructure matching usegalaxy.org - supervisor, uwsgi, and nginx. -RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transport-https software-properties-common && \ +RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transport-https software-properties-common && \ apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 && \ sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" && \ apt-get update -qq && apt-get upgrade -y && \ From 9fe6f561f7ba00b76fca1c6a08835fa98316fc84 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 18:54:03 +0100 Subject: [PATCH 31/71] wait longer for postgresql to startuup --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index a80d0b318..140a14860 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -147,7 +147,7 @@ RUN rm $PG_DATA_DIR_DEFAULT -rf RUN python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE ADD ./create_galaxy_user.py /usr/local/bin/create_galaxy_user.py -RUN service postgresql start && sleep 5 && python /usr/local/bin/create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin +RUN service postgresql start && sleep 10 && python /usr/local/bin/create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin ADD ./startup.sh /usr/bin/startup # Script that enables easier downstream installation of tools (e.g. for different Galaxy Docker flavours) From 83a444f3041ae0bcb24d719ee207e2a1b717a44c Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sun, 1 Feb 2015 18:54:55 +0100 Subject: [PATCH 32/71] Updated role. --- galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index 97915bc7e..0177da129 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit 97915bc7e791d3755c140fb1802e56800ae27da9 +Subproject commit 0177da129de372f1af191af623e43486c9f74610 From 394753be7c2bf7ab7bf209dd96e9e8aa4fec2ab9 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Tue, 3 Feb 2015 17:23:25 +0100 Subject: [PATCH 33/71] improve installation wrapper --- galaxy/install_repo_wrapper.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/install_repo_wrapper.sh b/galaxy/install_repo_wrapper.sh index 8dcecd33c..4cff5286b 100644 --- a/galaxy/install_repo_wrapper.sh +++ b/galaxy/install_repo_wrapper.sh @@ -8,7 +8,7 @@ sudo -E -u galaxy ./run.sh --daemon --log-file=$install_log --pid-file=galaxy_in galaxy_install_pid=`cat galaxy_install.pid` while : ; do - tail -n 2 $install_log | grep -q "Removing PID file galaxy_install.pid" + tail -n 2 $install_log | grep -E -q "Removing PID file galaxy_install.pid|Daemon is already running" if [ $? -eq 0 ] ; then echo "Galaxy could not be started." echo "More information about this failure may be found in the following log snippet from galaxy_install.log:" @@ -37,6 +37,6 @@ if [ $exit_code != 0 ] ; then fi # stop everything -./run.sh --stop-daemon +sudo -E -u galaxy ./run.sh --stop-daemon --log-file=$install_log --pid-file=galaxy_install.pid rm $install_log service postgresql stop From b58f6715cb44796d9d03ffd4c85bceff48adb732 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Tue, 10 Feb 2015 18:26:02 +0100 Subject: [PATCH 34/71] Move all ENV instructions into one Docker command to not exceed the parent docker image limit of 127 --- galaxy/Dockerfile | 58 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 140a14860..82a3abd50 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -86,38 +86,38 @@ RUN . $GALAXY_VIRTUALENV/bin/activate && python scripts/fetch_eggs.py -c $GALAXY # Updating genome informations from UCSC #RUN export GALAXY=/galaxy-central && sh ./cron/updateucsc.sh.sample -ENV GALAXY_CONFIG_DATABASE_CONNECTION postgresql://galaxy:galaxy@localhost:5432/galaxy -ENV GALAXY_CONFIG_TOOL_DEPENDENCY_DIR ./tool_deps -ENV GALAXY_CONFIG_ADMIN_USERS admin@galaxy.org -ENV GALAXY_CONFIG_MASTER_API_KEY HSNiugRFvgT574F43jZ7N9F3 -ENV GALAXY_CONFIG_BRAND Galaxy Docker Build -ENV GALAXY_CONFIG_STATIC_ENABLED False -ENV GALAXY_CONFIG_JOB_WORKING_DIRECTORY /export/galaxy-central/database/job_working_directory -ENV GALAXY_CONFIG_FILE_PATH /export/galaxy-central/database/files -ENV GALAXY_CONFIG_NEW_FILE_PATH /export/galaxy-central/database/files -ENV GALAXY_CONFIG_TEMPLATE_CACHE_PATH /export/galaxy-central/database/compiled_templates -ENV GALAXY_CONFIG_CITATION_CACHE_DATA_DIR /export/galaxy-central/database/citations/data -ENV GALAXY_CONFIG_CLUSTER_FILES_DIRECTORY /export/galaxy-central/database/pbs -ENV GALAXY_CONFIG_FTP_UPLOAD_DIR /export/galaxy-central/database/ftp -ENV GALAXY_CONFIG_FTP_UPLOAD_SITE galaxy.docker.org -ENV GALAXY_CONFIG_USE_PBKDF2 False -ENV GALAXY_CONFIG_NGINX_X_ACCEL_REDIRECT_BASE /_x_accel_redirect -ENV GALAXY_CONFIG_NGINX_X_ARCHIVE_FILES_BASE /_x_accel_redirect -ENV GALAXY_CONFIG_NGINX_UPLOAD_STORE /tmp/nginx_upload_store -ENV GALAXY_CONFIG_NGINX_UPLOAD_PATH /_upload -ENV GALAXY_CONFIG_DYNAMIC_PROXY_MANAGE False -ENV GALAXY_CONFIG_VISUALIZATION_PLUGINS_DIRECTORY config/plugins/visualizations -ENV GALAXY_CONFIG_TRUST_IPYTHON_NOTEBOOK_CONVERSION True -ENV GALAXY_CONFIG_TOOLFORM_UPGRADE True +ENV GALAXY_CONFIG_DATABASE_CONNECTION=postgresql://galaxy:galaxy@localhost:5432/galaxy \ +GALAXY_CONFIG_TOOL_DEPENDENCY_DIR=./tool_deps \ +GALAXY_CONFIG_ADMIN_USERS=admin@galaxy.org \ +GALAXY_CONFIG_MASTER_API_KEY=HSNiugRFvgT574F43jZ7N9F3 \ +GALAXY_CONFIG_BRAND="Galaxy Docker Build" \ +GALAXY_CONFIG_STATIC_ENABLED=False \ +GALAXY_CONFIG_JOB_WORKING_DIRECTORY=/export/galaxy-central/database/job_working_directory \ +GALAXY_CONFIG_FILE_PATH=/export/galaxy-central/database/files \ +GALAXY_CONFIG_NEW_FILE_PATH=/export/galaxy-central/database/files \ +GALAXY_CONFIG_TEMPLATE_CACHE_PATH=/export/galaxy-central/database/compiled_templates \ +GALAXY_CONFIG_CITATION_CACHE_DATA_DIR=/export/galaxy-central/database/citations/data \ +GALAXY_CONFIG_CLUSTER_FILES_DIRECTORY=/export/galaxy-central/database/pbs \ +GALAXY_CONFIG_FTP_UPLOAD_DIR=/export/galaxy-central/database/ftp \ +GALAXY_CONFIG_FTP_UPLOAD_SITE=galaxy.docker.org \ +GALAXY_CONFIG_USE_PBKDF2=False \ +GALAXY_CONFIG_NGINX_X_ACCEL_REDIRECT_BASE=/_x_accel_redirect \ +GALAXY_CONFIG_NGINX_X_ARCHIVE_FILES_BASE=/_x_accel_redirect \ +GALAXY_CONFIG_NGINX_UPLOAD_STORE=/tmp/nginx_upload_store \ +GALAXY_CONFIG_NGINX_UPLOAD_PATH=/_upload \ +GALAXY_CONFIG_DYNAMIC_PROXY_MANAGE=False \ +GALAXY_CONFIG_VISUALIZATION_PLUGINS_DIRECTORY=config/plugins/visualizations \ +GALAXY_CONFIG_TRUST_IPYTHON_NOTEBOOK_CONVERSION=True \ +GALAXY_CONFIG_TOOLFORM_UPGRADE=True \ # Next line allow child docker container for viz to find this docker container. -ENV GALAXY_CONFIG_GALAXY_INFRASTRUCTURE_URL http://$HOST_IP/ -ENV GALAXY_CONFIG_SANITIZE_ALL_HTML False -ENV GALAXY_CONFIG_TOOLFORM_UPGRADE True -ENV GALAXY_CONFIG_OVERRIDE_DEBUG False +GALAXY_CONFIG_GALAXY_INFRASTRUCTURE_URL=http://$HOST_IP/ \ +GALAXY_CONFIG_SANITIZE_ALL_HTML=False \ +GALAXY_CONFIG_TOOLFORM_UPGRADE=True \ +GALAXY_CONFIG_OVERRIDE_DEBUG=False # Define the default postgresql database path -ENV PG_DATA_DIR_DEFAULT /var/lib/postgresql/9.3/main/ -ENV PG_DATA_DIR_HOST /export/postgresql/9.3/main/ +ENV PG_DATA_DIR_DEFAULT=/var/lib/postgresql/9.3/main/ \ +PG_DATA_DIR_HOST=/export/postgresql/9.3/main/ # Install all required Node dependencies. This is required to get proxy support to work for Interactive Environments From f251fba58f83eb8ef44d41b6669561104d00786f Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Tue, 10 Feb 2015 18:38:25 +0100 Subject: [PATCH 35/71] Move all ENV instructions into one Docker command; Add GALAXY_DEFAULT_ADMIN* variables. --- galaxy/Dockerfile | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 82a3abd50..4ac6c8f61 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -25,18 +25,22 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo nano nmap lynx vim curl python-pip && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -ENV GALAXY_RELEASE default -ENV GALAXY_ROOT /galaxy-central -ENV GALAXY_CONFIG_DIR /etc/galaxy -ENV GALAXY_CONFIG_FILE $GALAXY_CONFIG_DIR/galaxy.ini -ENV GALAXY_CONFIG_JOB_CONFIG_FILE $GALAXY_CONFIG_DIR/job_conf.xml -ENV GALAXY_CONFIG_JOB_METRICS_CONFIG_FILE $GALAXY_CONFIG_DIR/job_metrics_conf.xml -ENV GALAXY_VIRTUALENV /home/galaxy/venv -ENV GALAXY_USER galaxy -ENV GALAXY_UID 1450 -ENV GALAXY_GID 1450 -ENV GALAXY_HOME /home/galaxy -ENV EXPORT_DIR /export +ENV GALAXY_RELEASE=default \ +GALAXY_ROOT=/galaxy-central \ +GALAXY_CONFIG_DIR=/etc/galaxy \ +GALAXY_CONFIG_FILE=$GALAXY_CONFIG_DIR/galaxy.ini \ +GALAXY_CONFIG_JOB_CONFIG_FILE=$GALAXY_CONFIG_DIR/job_conf.xml \ +GALAXY_CONFIG_JOB_METRICS_CONFIG_FILE=$GALAXY_CONFIG_DIR/job_metrics_conf.xml \ +GALAXY_VIRTUALENV=/home/galaxy/venv \ +GALAXY_USER=galaxy \ +GALAXY_UID=1450 \ +GALAXY_GID=1450 \ +GALAXY_HOME=/home/galaxy \ +GALAXY_DEFAULT_ADMIN_USER=admin@galaxy.org \ +GALAXY_DEFAULT_ADMIN_PASSWORD=admin \ +GALAXY_DEFAULT_ADMIN_KEY=admin \ +EXPORT_DIR=/export + RUN groupadd -r $GALAXY_USER -g $GALAXY_GID && \ useradd -u $GALAXY_UID -r -g $GALAXY_USER -d $GALAXY_HOME -c "Galaxy user" $GALAXY_USER && \ @@ -147,7 +151,7 @@ RUN rm $PG_DATA_DIR_DEFAULT -rf RUN python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE ADD ./create_galaxy_user.py /usr/local/bin/create_galaxy_user.py -RUN service postgresql start && sleep 10 && python /usr/local/bin/create_galaxy_user.py --user admin@galaxy.org --password admin -c $GALAXY_CONFIG_FILE --key admin +RUN service postgresql start && sleep 10 && python /usr/local/bin/create_galaxy_user.py --user $GALAXY_DEFAULT_ADMIN_USER --password $GALAXY_DEFAULT_ADMIN_PASSWORD -c $GALAXY_CONFIG_FILE --key $GALAXY_DEFAULT_ADMIN_KEY ADD ./startup.sh /usr/bin/startup # Script that enables easier downstream installation of tools (e.g. for different Galaxy Docker flavours) From c68fc9874f68635894f937c528526979a30eeb46 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Wed, 11 Feb 2015 00:18:07 +0100 Subject: [PATCH 36/71] Fix a bug in new ENV vars. --- galaxy/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 4ac6c8f61..ce5fba6cb 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -27,8 +27,9 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo ENV GALAXY_RELEASE=default \ GALAXY_ROOT=/galaxy-central \ -GALAXY_CONFIG_DIR=/etc/galaxy \ -GALAXY_CONFIG_FILE=$GALAXY_CONFIG_DIR/galaxy.ini \ +GALAXY_CONFIG_DIR=/etc/galaxy + +ENV GALAXY_CONFIG_FILE=$GALAXY_CONFIG_DIR/galaxy.ini \ GALAXY_CONFIG_JOB_CONFIG_FILE=$GALAXY_CONFIG_DIR/job_conf.xml \ GALAXY_CONFIG_JOB_METRICS_CONFIG_FILE=$GALAXY_CONFIG_DIR/job_metrics_conf.xml \ GALAXY_VIRTUALENV=/home/galaxy/venv \ @@ -41,7 +42,6 @@ GALAXY_DEFAULT_ADMIN_PASSWORD=admin \ GALAXY_DEFAULT_ADMIN_KEY=admin \ EXPORT_DIR=/export - RUN groupadd -r $GALAXY_USER -g $GALAXY_GID && \ useradd -u $GALAXY_UID -r -g $GALAXY_USER -d $GALAXY_HOME -c "Galaxy user" $GALAXY_USER && \ mkdir $EXPORT_DIR $GALAXY_HOME && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_HOME $EXPORT_DIR && \ @@ -158,7 +158,7 @@ ADD ./startup.sh /usr/bin/startup ADD install_repo_wrapper.sh /usr/bin/install-repository RUN chmod +x /usr/bin/install-repository /usr/bin/startup -# This needs to happen here and not above, otherwise the Galaxy start +# This needs to happen here and not above, otherwise the Galaxy start # (without running the startup.sh script) will crash because integrated_tool_panel.xml could not be found. ENV GALAXY_CONFIG_INTEGRATED_TOOL_PANEL_CONFIG /export/galaxy-central/integrated_tool_panel.xml From e79ce1c6ee77921cc9fda791402b17e328693f4a Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Wed, 11 Feb 2015 00:18:46 +0100 Subject: [PATCH 37/71] Add workaround for bug: https://github.com/docker/docker/issues/783#issuecomment-56013588 --- galaxy/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index ce5fba6cb..851a1ab10 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -148,6 +148,10 @@ ADD ./export_user_files.py /usr/local/bin/export_user_files.py # 3. Create Galaxy Admin User 'admin@galaxy.org' with password 'admin' and API key 'admin' RUN service postgresql stop RUN rm $PG_DATA_DIR_DEFAULT -rf + +# workaround for a Docker AUFS bug: https://github.com/docker/docker/issues/783#issuecomment-56013588 +RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private + RUN python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE ADD ./create_galaxy_user.py /usr/local/bin/create_galaxy_user.py From af6c241b1dff493ed70e5dc726ee83defb325949 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Wed, 11 Feb 2015 10:22:55 +0100 Subject: [PATCH 38/71] Stick to a fixed docker version to give our users time to upgrade their clusters. --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 851a1ab10..4e020db62 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -20,7 +20,7 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo apt-get -qq update && \ apt-get purge -y software-properties-common && \ apt-get install --no-install-recommends -y mercurial python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv wget \ - nginx-extras uwsgi uwsgi-plugin-python supervisor lxc-docker slurm-llnl slurm-llnl-torque libswitch-perl \ + nginx-extras uwsgi uwsgi-plugin-python supervisor lxc-docker-1.4.1 slurm-llnl slurm-llnl-torque libswitch-perl \ slurm-drmaa-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools ansible \ nano nmap lynx vim curl python-pip && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* From b5b59fa1c764aa8acd2047daeec1e9c966abf1d1 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 20 Feb 2015 20:32:02 +0100 Subject: [PATCH 39/71] Add chart to explain the docker hierarchy --- chart.png | Bin 0 -> 185452 bytes chart.svg | 721 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 721 insertions(+) create mode 100644 chart.png create mode 100644 chart.svg diff --git a/chart.png b/chart.png new file mode 100644 index 0000000000000000000000000000000000000000..12ff77fb19c17df939dbad289b5acdd65e2647c3 GIT binary patch literal 185452 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

g7cB0U%VZ;!IuK|Pgc{LNu+ne_m0O;X2`~B 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 z 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ℭ!FB+7=Xla6NO+0W{t7`|hz0N1<}BqLB_Qv*p3Fr)N<4pWFrbZ~dbxH) z@W>M};-xwgpT6t}D4c0!2e7xk;RYn| z+t^*<LuLI1^CGa!6=MIdPRB$Gq zcyy48L{IB_iDh*JB7?q*w(X8N!DJ;q&;b z(Yf;wDmrZwQY(pt`3^WmTESy?b&SV&|NG?i;?Xj9bPPw+Tcm^+{s~N92+lUFEYE5t z&Xw4*V<-y?7rW7A7*&;_)-Y`W=f-kxM$j<`QWg>SK~!^xV@rWz1JzIkqeobup2Bx~ z%&AqiQdY0MeKUvGcCxX30{ zSK3X2*)bzsqZ?zVtT*O&BaJ#av)1pBpzW8g$}X;wPMzV-N{3H#?QIHzOeFKwIl8iA z94y&(RVfv`;fd=`hi1ld_HSMiH*tH-vyWMI`EOmeg(}+>-JDC$OG?yWenyLn4DfM6 z8cR6;z~X94_a+!k1d)r_R4Y8hh`T9M@l8Gr6mTCOAKa+p+PedXeolXh{q2+$dr&Pf zxVe9SP@QGl$xx$Km@ME62Rmjbl#n-w?k+^xn5^r%TeEdqy1Ba}6@jogPv~F~B>vH~ zfVb}>ys8XSF@Rf$X{w2^il(luot?{9TUu$;eaJ=^_p3Juk@NBXLt5#)@^s-ni4DKm z?NQUn{s?lVXAGpsn5I^z_MD$%+6!ND|H|g%P}$m&tjW84)EXAF&ZiY7QZN5uO%l1- zopEUDr5lHA^!=!?w5$)+4gq`Jeo(&@$v`LqU^px)PhEzO5s9-X-oggvQxO&gXFC;% zkYfPM(8LgBZ zBK^blU}vX-vJ1koWZh9hJqI1iT||L;n7kT;V_mp(_*?bb3N76dJx)$2q#e#N(^Xf# z(J^@NydDDa(re`^;qj)kbZe zM$`P7QRrbva}4_%)j$GcF!=<JCB&)%hyW>EF6iu7`H!@*fAQhGW&M?+hTa?~^@fx|Yy#7*l}2o4SHc&tw#3;_5g ze>{pr@eI!mb#q`)&{t5?{sr*AnY)>8FtI_+XfOW3_S7l4Qzr~GS3Ydn@~dR5iF%%q zTh4gTw0`b$6v~J#;z0!l!VGRK9KN^Uxgr-#`_J2OCpE67wKe>wVh^n?v0uLDEy<#V zvk|OP8l?I>+Kq>u2*rRN9Dny&ahco zF|$SQ3>8^0{SHBn$r$F3TBjLt_|mtoFle3x)EQC>8Wmd5vj)xA&z4Rc8@z@n)svmf zRSnz!+RZkr!C}#t=^NgWb+WNPICT&4Vl98#Q>MLU`kil^3Km~rLf)wKW(@E$P*Xrw zM>#v_lXV3BTW8po)PmG>HS5OaAu+auy);jTZGu-1j8nK&$C6j{7GZ7Z5NeJ~?5JS1(=|xhVivWTflHwu{i_KnPL~i@YJXI(X>g zYt>`(hTK|qhY^B^pFE7VYA#by>dvR1?+gyeV3#Iji-o6!rKC6zC#>J8f^8K^wU64l z^#aGoUuuV~EKFv7)5wk%pL~A&spd7|9J#X@Bwusyr2y^%{+_ud^o45fjNc^Xt%L z-sjYdTseQWV1R(`5rQ;YzQSKgVGDr!rs55{!+19}awn2Qh(Z8^Rzu!R3rvvtDMR$X zW5*86u`?!|*}lVr2_ah*NI{0&7;>|m8$7)I0)cKsOOkLL>bgB^eCa#a8k}md3j;&4eg{1 zIObu7Zan0@2gv;tsXQps9*hb|masUNu|!@WyD>!*o_XZMSL0a!{7EAe(v_d5b!Rv% z8iJm781VHLEq{Haa3!-xPj=#jkQ_{FVISic-8aaH8ZI(AF76K1m9d(E7u$$O*g?@z z%@)4D+U{c)a_pJXE%FVwWPZAO(3&u&O= zZHjOPDsRLX;oX0ctC}Lb$z3ZQj~FL3GL^)Cqm(ytK%vr8qP0Yk3sn*2FlNoBBjU#F<0RSe9E$9DL%GJD*?9?h5`N zyB3g_|DF^*QTqcXLYx%ULOIB)c4UTyy?=>n4?y-4Hero|kEeCdiCsIh{i`dnD2lOe z$?$Ie?i=(`_OH%1KMFYq3YHST%ScSQnNm&pJeS-d^t@`tlb_WC>PAMw2WIZrlP;UF z9WIyGGh`%t!^%R-9W}Ubom!!5*KGeZz1DLkZN~`jQo0#Q#(av{hYu-8zi%|rSa(iH zE)F-bzw%z#M8Z__ZfBm{ud(w2vERSn>Mnd(R6F^5yQ`(__V?*I#_? z^-ch3V_f2`{jfhi4V5yXFZCiqpWWoM+)gWb1$Svt85rGX)Q?d0PCwdn8si zRncvsH(+B%VT*~V7_wiJD-!aJ*Du$xm$45lN?IJh$gW{n(!yAp(e^DSO-qmRvBJTc z*V_*te#x`o%lh*y;=l}e=sMdm#wE$ z!$iQ-30XJ)%1ZhAh@_9%%h&!)d>)B?y<)NV+{qwYux)MstaG70X>wa%^)jvWCWvB? z0{O!w0p7AW5UVHRrL@0aHig}l*iV7$f}}GQD)w05-w@?I;;XK8>Qn<%_AEFJ0apP| zCt;!_+#@Jb1@0#`kD_p=AU*Y*F(c%g5Y)r|1Z$Hr=DD-LkXeDGMw*D$A@pm|*W61? zBy^wVAeHo>Bmaqp9mn}Pbk~NUnT2RjGwcWwFd@lOg_aBh=PJnPG2g%x>nn;fHg`t~ z_nRV+S>6J$OW??nt=Pd4mqbMPAd?~-sj4AjKA%}|gnnCBM@E9Y_XbFCw=?`uSdaIW zKkq4mrvZz^HsDPt(CNUzkvQ%?F{?EB=^2d?&?@NTw?jgdk)DZ$BZ2rJ$N|u;+PSr~ zr)OmiL*-0}AqYYb9DjIYK+9v#R5ZzsPRU52 zP{tVsg($8O@p&NIrvqvaY$o%rCuja)2pc1o^fo2|jHvyIs4*}D3A!7eixl9p^qPV7 zsKT3%4HjIVqlh+wun#FfyNRGI7}(Wu;2nLTwI|}=RtYa+n>5!}SKn3GWB5f$qQmIW zUD$wrWvubgTx0Q>okPdC=(LV=uF#!&&(HkKwNdem*T`|R%^`b51UEQWBeS=^-o12X ze4p-$A9=-*SDKPEBjsfDX^-wq87|9a5~x90 zXGVecSHpwJ#=S*tj}`{HfRAm4s8r8gIG-S`kSQTPHGM*dTWtUS2!fIPyPuw91L~kI z+PG`-J9elQw7dFq?Wppfm= z&4j`xas&N_w@poVNcm8V=r;)|wn9zNvBx9bbxV1U(X+)(J|; zlu6ijMYE|@p!Di`eV2ddeDaIO-QA3*Sl0|%iK6-SZ=w4&yu8YfmIKp>tJB=9HFXs> ztL!Pr8Pzr%p&&X6*7y@Mg{1wuPTJaxXK=nodRwZU4FcLkE+gY7ARypv6Q1W#v-8lx zKggbkD>e|BQTXD}uJ2orDHg)ZOG$zvVY93+$}e(%3|n)A4|ambQ#4*8biI;pP?h+~ zFz4+gy@PCKR}=Ucq5WGPoyhE2%f%u)0+6BJm-nr$LQu52&SW7bo^8}`VIpc=I=FUo zULHD?07pF_@gtQGMW$+`k)ffQlw+T;$DjnN=*|pu_`bqJjgTU$z!uD-q?qCW0% zYq`5if*rfLpC+i=glk)9-42+`SVzI&x(!gcuo;m2b0Cz4^q;y|8E*0%W@lE?2u|3! zOrr^UMn>qX;@o)r`t?^elf(qf~g|&=!53j4YmlEdFM%o<~1(JcTmVb{v>B3=JPziZ^O0 z7w$eSuJ(pC*l&4r9_RbhBYX7NI`8D4oe4YD5W%@tiDK(~YplSFyAg?rz7Hoa7I7;5TK#-u%HbJ6vDiv3Z)A=2E-zW)Me1$@pXnKC-)wh82t2!4c6~1p+!g< zgpHek=|BTnWZRj0tN}5jw;+lmCjltxkFbNHq-8q{T*_JfR)5jpv2%t=0DUP!6N+c~ zDE1O!g>T&WNpEx>Jv*V3kI~y>fJyBemT$BZh?6bB;goXd9l~C<_&we!&TTD_AYKyt z3Z5ts<4N)F>!JNbkZuUb8wBo@^&+6m=xTWQvjpIUPQ!J=71z+xx(VYS(1$~~84$zh zK0={DSp1awxrg9h~W1$GG~Y*ZMW5?>R=E`YR_ z&`uw024#{P&9slefML_By7ZhdrHqeT1Gz@jAb^=rCVk-Ci=cO+q#_~;hzMEt2{v%& z?OaNNoPe0oebS@Y^&;<$ow95^qN}`Yxe{^CMmXE7z z%aVY`5#S$OO#(*v=~HoA5xM){kC-V{b#}6YN`^n=-tStQcba&lz+5cDMEqzuj>3fX z38h&b_J+EG1!bJSe3Kx;6I$H5j78cR&qD@(p!DASYw4TIOdW3u28`dO zpRl>UW68FT`=DLP;U%%(FWydtE-TV(SJ?eT{&1XRp2}iv&o9m*rg%a%*d+MW??e=~vw>(n5m0MF~V?Exq{Q9HEM||S&;z{JT zqCh?NzSuc_*(+@_eSq0Xb~qr_WcSXU61gYV zwsPVX62ifj)eDA>lcalauixe^%+1|_?=47r2Rur8*LE&04H64>G(CiH%9#1pt0gJ; z?Cc$NEw>c>g)4R{DEtlPHjjTW-2 zrxFN6L(reZ56*AonZGE3)dX+gp%%HH7$3ivTmJQxv6Dr`n2TVmL=GPwi;!pNvawW} zVF7>J&V6VYi-><@v}S9d{MFfH;mY-F1EyeAIOdc{_aF(@h|DV}5W<-epB^z9yW0Ev z`{_uQ7cZ*e@zHQ_5OeYH5F))pF?bvUhog_WZnu`PjLppK_m;2p(w@jtZMsV=W^KZ& zSVBXd;ki%!`x7hG+ji_i>LeDVe9j>k;#i%CLwz0Ax)8`v#`#RnoY|v$4B2T&U48Un z9PhO%i3Mk}qT!mYoTPU+>~3Qpjt@MvkA&b;&K$3+a*5XUp~atR16f>Qgd+Dx9Oj+= z58LIg^8X!FioSKpl*A9Z@GkNjN~u#=Xz54?5zJIHjEmNI&@*c5=)l*;E#>xMnz`8}F^s<9$%)IssaR};N8|2pJACrz-y5YRz?G+FW*X&Z z-Zr~eO2C;3J15aia~J+3+fqHiw0qUJ293+AHVPW&wF$|QcURx{yy&P=9t$6L==)tV z@MSEkMr2xm`Y82~mcDt%n3c2l#)rig_o=gqWNNxIdvTQ>%dy|Kadb?zLgz@@?}Ul_6(^iq$)@UE*7+jMF2Ja>C?^)tx4EblN}XrE+csF4%F8~cmuW`y~)Rj zqry|+k464b8WF*~x2*uJTBrlbNl;X9hArni0k2Q;2NHQ{x6ubo10k*t!Bp2A!6IS% zc1M864Lv<2NkcmP?8H!BAtxT?wz9DBM+0K=hAcb2 zNWh_g0Z@5XRFrBcM=-#R=lOzI8~$QD>o%Av?o#cqdbuBeRfa6KayM-`->!mwI$ z^avW*+8eFjmB=sy*w6SSQW}Zqqn4HvsN84(qfiD}9Iz*65PrlTwFo6qEd1Q^x&W@a zJ1`C%Pyg`fkh;BM+%o=J#8!MH4vuh|@90Oy4N+IwscT4wTEWE5y7FGa2t!0*?QQ|* z_~cv#2fo;Y9{L7sR3N=VGC~l)K6wW|FGq(|cdykcT_>lROLaZ5GFa|FMx(>D@6k#( zG2wt>1vo&~l_x}o3!X)&`7+kGy$VBim`4AHONjF%@%QE(9|!0W2ghK5tC8HgaXerD zYCh`1AS}ov_iN55#woJDSl#qKTx9%&V~Gb2i(3#+_OxiIfv#RTen@94hnNZF`SXKn zC$?>icL#M{plvlpOo=Job#T&iCF)vM?(Ybb)TZ*$Qy8X=w zOlB)Xa#C*eE3Twmxx8(vZ)uC|h3lDgx07`j=qR7fACQ!IdMS)EI^VeMiE$2dJZ=`Y zS^^<%7_6cjrgC`S^*6}2pzv>@Imq~1B7I^?`&V3KkV5T8Nie z)=ttYqkVfXK0Xxo!P@F-Wu!qhkZ$uGlVamUj{xq5Pr-3ctO{=2pjCf5$?XMZsq>$y zGXz5(1Y%TroIVXikhOoNd#c1O=SCbGc0cmM%_#C&@c_=5Jdg!z6qsV)I`dAuHs|K# zR5v!#;pAYcbx1P$snri{B=>TOo0Et~^Up_}#cMcmn`10kV!syFhl2`Xb88zsBg%n> zXRze33ZM)wpS+Zlt+;a0zof&ZVj&;?4!1)V5$N$sCv)n7|OW5h}MMqQLP$EG| zfb1#ViudPyrvNLO{rx)-xB;|vF6<){d=(LgKq3(l&8dMi8z2GEz+-`a7cgU+^AH

!lnqcm)7qpZwO5}}OB$lfDKOC>up5~-As z9W64mWh9aj+5FE}pU?OEJkS3bpW}BNzrJPM_x*m2>pIW#I#0g0DL^dUSk259r|;)+ z17ap|<3|cVvnzw%Wk%o(KEN<}cmL`30Z+;54a58maN!05CW!f164Zd*LTRv5Wp23o z;$1-#w0bb=Q2`!o&H5H}!bNN?VgZk@D#fNFuF25KN-Vrd8vrhMKC1uq-J_2hMC&?l zznQ-&3^(fk3nEv~VxM03;b^PnQuw*M3YI)ig1Rb4=2Xcqr@`m-&Zdh3aUpiRWQU4K2W( z#2^tw22oJ2eMxrX752EYX>@rSrpXjieZTQs&u81!_iK4ndlQL$e_PG5z{QT9uN z4Gt=%dvR&0p?8JCa#P(!ss@)LPiO%Wqk3Swcw$DveyF3Q=K|7bS>k_{6m7{h4Ljz# z498HRojcjdfC5aC(Tc$50{#Ogil+RBl(HI^- z8^MbR(8Y&tlY`ngnlyjj1<089JS96#{;(7<1yKM7ogWgV^nrv&E)GL7JB1Ta+9RU)HQ&cDu#*Q{ezq zSzFlz)U*X2qBHo`9uPM3J5u4o*jvxNt_ub?D{t;Ne(;`LYB+4WPW5~fy({gSt8AIF ze=kWCM88WOs|;h@=b+S7ada#qPA6BVPo*!j7N`6=QcBm0e!CJ)4DW|+w$A5|u$iVl zGEPE~?eXX9S!mdxM&Z>%`G1d=N2`v;R*lybBx%Sx%a*w+890Y`h7IA>m01Jh(1w(tshH`~M z#TGt4N2EKfO>cER6h`;f0|~=1!!H{ld%{o&DwG36YAX8Z-cHK|DNMJ8q8ky0mA}

qBBBH0acLhd)NC+Vo(#?0xFys&s5qS$Tt7lqU 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

lmwV`2)5njayU(Z6 zsK}d97<)x*aa3Qo$CG=95_5zc#b$e)sMJ>t9tK5{HFdj9s(m!XNCVk9s*pmMBo=O7UZY7lG{p^#sD(psALkEb?;OI*K z?A3}IE!KEK0UH@a7mEd}uNSA(+p=+Pk5qSo_Tj(&>6=BxagZfq;!GK9ddL%42+%*B zw$ZTDUk{NMk=q^Nr6|_tHavcekMAYv6V65B3yha8UVgrO)oHTGecto)6#Omp^M3>C CPT|b} literal 0 HcmV?d00001 diff --git a/chart.svg b/chart.svg new file mode 100644 index 000000000..64348907b --- /dev/null +++ b/chart.svg @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + docker-ipython-notebook + + + + + + + + + + + + + + + + + + galaxy-stable + docker-galaxy-stable + + + + + + + + + + galaxy-proteomics + docker-recipes + + + + + + chemicaltoolbox + docker-recipes + + rna-workbench + galaxy-rna-workbench + + + docker-ipython-notebook + + + docker-ipython-notebook plus + docker-recipes + + + + + + + + + + + + + + + + + + + + + + + + + docker-ipython-notebook + + docker-galaxy-requirements + + + + + + + + + + From 23056d8726ef6fb11d719014ad083ed427ed4516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Fri, 20 Feb 2015 20:43:07 +0100 Subject: [PATCH 40/71] Include the docker image hierarchy chart. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d2647ff5b..a4188f0c1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ One of the main goals is to make the access to entire tool suites as easy as pos this includes the setup of a public available webservice that needs to be maintained, or that the Tool-user needs to either setup a Galaxy Server by its own or to have Admin access to a local Galaxy server. With docker, tool developers can create their own Image with all dependencies and the user only needs to run it within docker. -The Image is based on [Ubuntu 14.04 LTS](http://releases.ubuntu.com/14.04/) and all recommended Galaxy requirements are installed. +The Image is based on [Ubuntu 14.04 LTS](http://releases.ubuntu.com/14.04/) and all recommended Galaxy requirements are installed. The following chart should illustrate the [Docker](http://www.docker.io) image hierarchy we have build to make is as easy as possible to build on different layers of our stack and create many exciting Galaxy flavours. + +![Docker hierarchy](chart.png) Usage From 89c76ec9d6ea74dd98d8bdf1dda006d3ab9aebb0 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 27 Feb 2015 09:57:04 +0100 Subject: [PATCH 41/71] small optimizations and cleanups --- galaxy/Dockerfile | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 4e020db62..da83035a7 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -14,15 +14,14 @@ MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transport-https software-properties-common && \ apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 && \ sh -c "echo deb https://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list" && \ - apt-get update -qq && apt-get upgrade -y && \ apt-add-repository -y ppa:ansible/ansible && \ apt-add-repository -y ppa:galaxyproject/nginx && \ - apt-get -qq update && \ - apt-get purge -y software-properties-common && \ + apt-get update -qq && apt-get upgrade -y && \ apt-get install --no-install-recommends -y mercurial python-psycopg2 postgresql-9.3 sudo samtools python-virtualenv wget \ nginx-extras uwsgi uwsgi-plugin-python supervisor lxc-docker-1.4.1 slurm-llnl slurm-llnl-torque libswitch-perl \ slurm-drmaa-dev proftpd proftpd-mod-pgsql libyaml-dev nodejs-legacy npm aufs-tools ansible \ nano nmap lynx vim curl python-pip && \ + apt-get purge -y software-properties-common && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ENV GALAXY_RELEASE=default \ @@ -142,17 +141,15 @@ RUN locale-gen en_US.UTF-8 && dpkg-reconfigure locales ADD ./setup_postgresql.py /usr/local/bin/setup_postgresql.py ADD ./export_user_files.py /usr/local/bin/export_user_files.py +# workaround for a Docker AUFS bug: https://github.com/docker/docker/issues/783#issuecomment-56013588 +#RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private + # Configure PostgreSQL # 1. Remove all old configuration # 2. Create DB-user 'galaxy' with password 'galaxy' in database 'galaxy' # 3. Create Galaxy Admin User 'admin@galaxy.org' with password 'admin' and API key 'admin' -RUN service postgresql stop -RUN rm $PG_DATA_DIR_DEFAULT -rf - -# workaround for a Docker AUFS bug: https://github.com/docker/docker/issues/783#issuecomment-56013588 -RUN mkdir /etc/ssl/private-copy; mv /etc/ssl/private/* /etc/ssl/private-copy/; rm -r /etc/ssl/private; mv /etc/ssl/private-copy /etc/ssl/private; chmod -R 0700 /etc/ssl/private; chown -R postgres /etc/ssl/private -RUN python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT +RUN rm $PG_DATA_DIR_DEFAULT -rf && python /usr/local/bin/setup_postgresql.py --dbuser galaxy --dbpassword galaxy --db-name galaxy --dbpath $PG_DATA_DIR_DEFAULT RUN service postgresql start && sh create_db.sh -c $GALAXY_CONFIG_FILE ADD ./create_galaxy_user.py /usr/local/bin/create_galaxy_user.py RUN service postgresql start && sleep 10 && python /usr/local/bin/create_galaxy_user.py --user $GALAXY_DEFAULT_ADMIN_USER --password $GALAXY_DEFAULT_ADMIN_PASSWORD -c $GALAXY_CONFIG_FILE --key $GALAXY_DEFAULT_ADMIN_KEY From 2e7716f45457c22e73914e3622f9331afcca2bf6 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Mon, 2 Mar 2015 20:04:33 +0100 Subject: [PATCH 42/71] Switch dev branch over to the new github repository. --- galaxy/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index da83035a7..8fdcf864a 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo apt-get purge -y software-properties-common && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -ENV GALAXY_RELEASE=default \ +ENV GALAXY_RELEASE=dev \ GALAXY_ROOT=/galaxy-central \ GALAXY_CONFIG_DIR=/etc/galaxy @@ -47,7 +47,7 @@ RUN groupadd -r $GALAXY_USER -g $GALAXY_GID && \ gpasswd -a $GALAXY_USER docker # Download latest stable release of Galaxy. -RUN mkdir $GALAXY_ROOT && wget -q -O - https://bitbucket.org/galaxy/galaxy-central/get/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_ROOT +RUN mkdir $GALAXY_ROOT && wget -q -O - https://github.com/galaxyproject/galaxy/archive/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_ROOT # TODO: ensure virtualenv as part of galaxy role RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" From 5d90b0eba37ce4134025333fcef2419e1361d37a Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 08:30:59 +0100 Subject: [PATCH 43/71] Move the welcome.html page into /etc/galaxy/ and override it as soon as we detect a new one under /export/. In fact this holds for all files starting with "welcome", e.g. images that you want to use in your start page. --- galaxy/Dockerfile | 5 +++-- galaxy/export_user_files.py | 9 +++++++++ galaxy/welcome.html | 7 ++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 8fdcf864a..a5e788180 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -116,6 +116,7 @@ GALAXY_CONFIG_TOOLFORM_UPGRADE=True \ GALAXY_CONFIG_GALAXY_INFRASTRUCTURE_URL=http://$HOST_IP/ \ GALAXY_CONFIG_SANITIZE_ALL_HTML=False \ GALAXY_CONFIG_TOOLFORM_UPGRADE=True \ +GALAXY_CONFIG_WELCOME_URL=$GALAXY_CONFIG_DIR/welcome.html \ GALAXY_CONFIG_OVERRIDE_DEBUG=False # Define the default postgresql database path @@ -127,8 +128,8 @@ PG_DATA_DIR_HOST=/export/postgresql/9.3/main/ RUN cd /galaxy-central/lib/galaxy/web/proxy/js && npm install # Container Style -ADD GalaxyDocker.png /galaxy-central/static/welcome/GalaxyDocker.png -ADD welcome.html /galaxy-central/static/welcome.html +ADD GalaxyDocker.png $GALAXY_CONFIG_DIR/welcome_image.png +ADD welcome.html $GALAXY_CONFIG_DIR/welcome.html # Switch back to User root USER root diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index fe9aff5f8..33937f6fc 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -45,6 +45,15 @@ def change_path( src ): if os.path.exists( '/export/.distribution_config/' ): shutil.rmtree( '/export/.distribution_config/' ) shutil.copytree( '/galaxy-central/config/', '/export/.distribution_config/' ) + + # Copy all files starting with "welcome" + # This enables a flexible start page design. + for filename in os.listdir('/export/'): + if filename.startswith('welcome'): + export_file = os.path.join( '/export/', filename) + image_file = os.path.join('/etc/galaxy/', filename) + shutil.copy(export_file, image_file) + if not os.path.exists( '/export/galaxy-central/' ): os.makedirs("/export/galaxy-central/") os.chown( "/export/galaxy-central/", int(os.environ['GALAXY_UID']), int(os.environ['GALAXY_GID']) ) diff --git a/galaxy/welcome.html b/galaxy/welcome.html index 3f0659973..767a4b056 100644 --- a/galaxy/welcome.html +++ b/galaxy/welcome.html @@ -3,18 +3,19 @@ - + +

Hello world! Your Galaxy Docker container is running...
- To customize this page edit static/welcome.html + To customize this page you can create a welcome.html page in your directory mounted to /export.

- +


From bcef8a93a31d28d7dc580446821d52e96624fa1b Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 16:09:10 +0100 Subject: [PATCH 44/71] Add initial htpasswd file. User and password is admin. --- galaxy/htpasswd | 1 + 1 file changed, 1 insertion(+) create mode 100644 galaxy/htpasswd diff --git a/galaxy/htpasswd b/galaxy/htpasswd new file mode 100644 index 000000000..1663ffbc8 --- /dev/null +++ b/galaxy/htpasswd @@ -0,0 +1 @@ +admin:WiBKbsJTSQ8dc From f6681124aacc26f1d315057e51bf0cbb5a284a6d Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 16:11:41 +0100 Subject: [PATCH 45/71] Add optional password protection to the Galaxy report webapp. This can be turned off with -e "DISABLE_REPORTS_AUTH=TRUE" --- galaxy/Dockerfile | 1 + galaxy/export_user_files.py | 5 +++++ galaxy/startup.sh | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 8fdcf864a..46b171a22 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -57,6 +57,7 @@ RUN mkdir -p $GALAXY_CONFIG_DIR && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CO RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE && \ cp $GALAXY_ROOT/config/reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" +ADD ./htpasswd /etc/nginx/htpasswd ADD ./servers.ini $GALAXY_CONFIG_DIR/servers.ini RUN cat $GALAXY_CONFIG_DIR/servers.ini >> $GALAXY_CONFIG_FILE && rm $GALAXY_CONFIG_DIR/servers.ini ADD roles/ /tmp/ansible/roles diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index fe9aff5f8..112716784 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -55,6 +55,11 @@ def change_path( src ): change_path('/galaxy-central/tool_deps/') change_path('/galaxy-central/tool-data/') change_path('/shed_tools/') + + if os.path.exists('/export/reports_htpassw'): + image_config = '/etc/galaxy/htpasswd' + shutil.copy(export_config, image_config) + try: change_path('/var/lib/docker/') except: diff --git a/galaxy/startup.sh b/galaxy/startup.sh index cb868dc12..a06dcda72 100644 --- a/galaxy/startup.sh +++ b/galaxy/startup.sh @@ -35,8 +35,18 @@ else fi if [ `echo ${GALAXY_LOGGING:-'no'} | tr [:upper:] [:lower:]` = "full" ] - then + then tail -f /var/log/supervisor/* /var/log/nginx/* /home/galaxy/*.log else tail -f /home/galaxy/*.log fi + +if [ "x$DISABLE_REPORTS_AUTH" == "x" ] + then + # Authentification is enabled by default. There should be /etc/nginx/htpasswd file. + else + # disable authentification by deleting the htpasswd file + rm /etc/nginx/htpasswd +fi + + From 24db6bdf0d2b838a78eef7d0c7279cc16c34aa1f Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 18:31:37 +0100 Subject: [PATCH 46/71] fix disable reports auth --- galaxy/startup.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/galaxy/startup.sh b/galaxy/startup.sh index a06dcda72..1100d3d77 100644 --- a/galaxy/startup.sh +++ b/galaxy/startup.sh @@ -41,10 +41,8 @@ if [ `echo ${GALAXY_LOGGING:-'no'} | tr [:upper:] [:lower:]` = "full" ] tail -f /home/galaxy/*.log fi -if [ "x$DISABLE_REPORTS_AUTH" == "x" ] +if [ "x$DISABLE_REPORTS_AUTH" != "x" ] then - # Authentification is enabled by default. There should be /etc/nginx/htpasswd file. - else # disable authentification by deleting the htpasswd file rm /etc/nginx/htpasswd fi From e9ba14909fa1fe1c2a21e840927e7187c5cb9900 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 18:35:11 +0100 Subject: [PATCH 47/71] update ansible submodule --- galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index 0177da129..cfe4238f2 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit 0177da129de372f1af191af623e43486c9f74610 +Subproject commit cfe4238f27e30cf3e5f5eb77c1ddb9a0985c50d2 From 472bba97e696283b739a0f318d1d978b4b253b23 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 18:46:08 +0100 Subject: [PATCH 48/71] enhance developer documentation --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a4188f0c1..3174a1343 100644 --- a/README.md +++ b/README.md @@ -146,9 +146,7 @@ docker container in production, please do not forget to change the user credenti Development =========== -This repository uses a git submodule to include Ansible roles maintained by the Galaxy project. - -https://github.com/galaxyproject/ansible-galaxy-extras +This repository uses a git submodule to include [Ansible roles](https://github.com/galaxyproject/ansible-galaxy-extras) maintained by the Galaxy project. You can clone this repository and the Ansible submodule with: @@ -156,6 +154,12 @@ You can clone this repository and the Ansible submodule with: git clone --recursive https://github.com/bgruening/docker-galaxy-stable.git ``` +Updating already existing submodules is possible with: + +``` +git submodule update --remote +``` + Requirements ============ From e722768c24049c14e12f3a25ebd58eba50a3fedf Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 22:15:24 +0100 Subject: [PATCH 49/71] update submodule --- galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index cfe4238f2..7fd21bc87 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit cfe4238f27e30cf3e5f5eb77c1ddb9a0985c50d2 +Subproject commit 7fd21bc876ab0335eff4511018e9a96e80be0ef4 From 6772c9bb62878dc380cab859ea8ca33f284f6b9d Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 22:16:12 +0100 Subject: [PATCH 50/71] Do not expose port 9003 from Galaxy report app. This is now served as :80/reports/ --- galaxy/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index d425d6c2f..a95c46cd6 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -167,12 +167,11 @@ ENV GALAXY_CONFIG_INTEGRATED_TOOL_PANEL_CONFIG /export/galaxy-central/integrated ADD ./cgroupfs_mount.sh /root/cgroupfs_mount.sh -# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9003 (Galaxy report app), 9002 (supvisord web app) +# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy), 9002 (supvisord web app) EXPOSE :80 EXPOSE :21 EXPOSE :8800 EXPOSE :9002 -EXPOSE :9003 # We need to set $HOME for some Tool Shed tools (e.g Perl libs with $HOME/.cpan) ENV HOME /home/galaxy From 6f6a4677f358e075f8db5493b5bf87cd2e3b4a21 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Fri, 6 Mar 2015 22:18:51 +0100 Subject: [PATCH 51/71] For the moment we need to ship our own report_wsgi.ini file. This can not be overwritten by ENV vars at the moment. Moreover this file will not be part of the next stable release and we need the latest additions. --- galaxy/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index a95c46cd6..fd84adff4 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -55,8 +55,8 @@ RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" # Setup Galaxy configuration files. RUN mkdir -p $GALAXY_CONFIG_DIR && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CONFIG_DIR -RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE && \ - cp $GALAXY_ROOT/config/reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" +RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE +ADD ./reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" ADD ./htpasswd /etc/nginx/htpasswd ADD ./servers.ini $GALAXY_CONFIG_DIR/servers.ini RUN cat $GALAXY_CONFIG_DIR/servers.ini >> $GALAXY_CONFIG_FILE && rm $GALAXY_CONFIG_DIR/servers.ini From 01779134d66658880fcf1b7070c3d8cef3e63bee Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 7 Mar 2015 00:09:17 +0100 Subject: [PATCH 52/71] Typo fix. --- galaxy/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index fd84adff4..0c3d9110d 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -55,8 +55,8 @@ RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" # Setup Galaxy configuration files. RUN mkdir -p $GALAXY_CONFIG_DIR && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CONFIG_DIR -RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE -ADD ./reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini" +RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE" +ADD ./reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini ADD ./htpasswd /etc/nginx/htpasswd ADD ./servers.ini $GALAXY_CONFIG_DIR/servers.ini RUN cat $GALAXY_CONFIG_DIR/servers.ini >> $GALAXY_CONFIG_FILE && rm $GALAXY_CONFIG_DIR/servers.ini From 5bd8e589a73128a79fe9ba76f0bf75756dd8b51e Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 7 Mar 2015 00:10:41 +0100 Subject: [PATCH 53/71] * restructure startup script * introduce NONUSE to specify services that we don't want to start (nodejs, reports, proftp) * add more verbose output and add some documentation --- galaxy/startup.sh | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/galaxy/startup.sh b/galaxy/startup.sh index 1100d3d77..8dd148441 100644 --- a/galaxy/startup.sh +++ b/galaxy/startup.sh @@ -7,33 +7,55 @@ cd /galaxy-central/ umount /var/lib/docker python /usr/local/bin/export_user_files.py $PG_DATA_DIR_DEFAULT + # Configure SLURM with runtime hostname. python /usr/sbin/configure_slurm.py +# $NONUSE can be set to include proftp, reports or nodejs +# if included we will _not_ start these services. +function start_supersisor { + /usr/bin/supervisord + sleep 5 + if [[ $NONUSE != *"proftp"* ]] + then + echo "Starting ProFTP" + supervisorctl start proftpd + fi + if [[ $NONUSE != *"reports"* ]] + then + echo "Starting Galaxy reports webapp" + supervisorctl start reports + fi + if [[ $NONUSE != *"nodejs"* ]] + then + echo "Starting nodejs" + supervisorctl start galaxy:galaxy_nodejs_proxy + fi +} + + # Try to guess if we are running under --privileged mode if mount | grep "/proc/kcore"; then echo "Disable Galaxy Interactive Environments. Start with --privileged to enable IE's." export GALAXY_CONFIG_INTERACTIVE_ENVIRONMENT_PLUGINS_DIRECTORY="" - /usr/bin/supervisord - sleep 5 + start_supersisor else echo "Enable Galaxy Interactive Environments." export GALAXY_CONFIG_INTERACTIVE_ENVIRONMENT_PLUGINS_DIRECTORY="config/plugins/interactive_environments" if [ x$DOCKER_PARENT == "x" ]; then #build the docker in docker environment bash /root/cgroupfs_mount.sh - /usr/bin/supervisord - sleep 5 + start_supersisor supervisorctl start docker else #inheriting /var/run/docker.sock from parent, assume that you need to #run docker with sudo to validate echo "galaxy ALL = NOPASSWD : ALL" >> /etc/sudoers - /usr/bin/supervisord - sleep 5 + start_supersisor fi fi +# Enable verbose output if [ `echo ${GALAXY_LOGGING:-'no'} | tr [:upper:] [:lower:]` = "full" ] then tail -f /var/log/supervisor/* /var/log/nginx/* /home/galaxy/*.log @@ -41,9 +63,11 @@ if [ `echo ${GALAXY_LOGGING:-'no'} | tr [:upper:] [:lower:]` = "full" ] tail -f /home/galaxy/*.log fi +# Disable authentication of Galaxy reports if [ "x$DISABLE_REPORTS_AUTH" != "x" ] then # disable authentification by deleting the htpasswd file + echo "Disable Galaxy reports authentification " rm /etc/nginx/htpasswd fi From 9336d9916d11b9506d06982c53636f07955022f4 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 7 Mar 2015 13:54:37 +0100 Subject: [PATCH 54/71] Code cleanups. welcome.html will be served from /etc/galaxy/ from now on. --- galaxy/export_user_files.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index b1e3c55e3..4abdf7ceb 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -58,16 +58,14 @@ def change_path( src ): os.makedirs("/export/galaxy-central/") os.chown( "/export/galaxy-central/", int(os.environ['GALAXY_UID']), int(os.environ['GALAXY_GID']) ) change_path('/galaxy-central/config/') - change_path('/galaxy-central/static/welcome.html') change_path('/galaxy-central/integrated_tool_panel.xml') change_path('/galaxy-central/display_applications/') change_path('/galaxy-central/tool_deps/') change_path('/galaxy-central/tool-data/') change_path('/shed_tools/') - if os.path.exists('/export/reports_htpassw'): - image_config = '/etc/galaxy/htpasswd' - shutil.copy(export_config, image_config) + if os.path.exists('/export/reports_htpasswd'): + shutil.copy('/export/reports_htpasswd', '/etc/nginx/htpasswd') try: change_path('/var/lib/docker/') From f6fd4cd16bf09527ded9bd0ce18c771f07d1b279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 7 Mar 2015 15:27:27 +0100 Subject: [PATCH 55/71] Update README.md * document more features * fix links * many style changes * include links to different Galaxy flavours --- README.md | 145 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 3174a1343..df8fb2172 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,20 @@ The Image is based on [Ubuntu 14.04 LTS](http://releases.ubuntu.com/14.04/) and Usage ===== -At first you need to install docker. Please follow the instruction on https://www.docker.io/gettingstarted/#h_installation +At first you need to install docker. Please follow the [very good instructions](https://www.docker.io/gettingstarted/#h_installation) from the Docker project. After the successful installation, all what you need to do is: -``docker run -d -p 8080:80 -p 8021:21 bgruening/galaxy-stable`` + ```sh + docker run -d -p 8080:80 -p 8021:21 bgruening/galaxy-stable + ``` I will shortly explain the meaning of all the parameters. For a more detailed description please consult the [docker manual](http://docs.docker.io/), it's really worth reading. Let's start: ``docker run`` will run the Image/Container for you. In case you do not have the Container stored locally, docker will download it for you. ``-p 8080:80`` will make the port 80 (inside of the container) available on port 8080 on your host. Same holds for port 8021, that can be used to transfer data via the FTP protocol. Inside the container a Apache Webserver is running on port 80 and that port can be bound to a local port on your host computer. With this parameter you can access your Galaxy instance via ``http://localhost:8080`` immediately after executing the command above. ``bgruening/galaxy-stable`` is the Image/Container name, that directs docker to the correct path in the [docker index](https://index.docker.io/u/bgruening/galaxy-stable/). ``-d`` will start the docker container in daemon mode. For an interactive session, you can execute: -``docker run -i -t -p 8080:80 bgruening/galaxy-stable /bin/bash`` + ```sh + docker run -i -t -p 8080:80 bgruening/galaxy-stable /bin/bash + ``` and run the ``` startup ``` script by yourself, to start PostgreSQL, Apache and Galaxy. @@ -32,7 +36,9 @@ Docker images are "read-only", all your changes inside one session will be lost Fortunately, this is as easy as: -``docker run -d -p 8080:80 -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` + ```sh + docker run -d -p 8080:80 -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable + ``` With the additional ``-v /home/user/galaxy_storage/:/export/`` parameter, docker will mount the folder ``/home/user/galaxy_storage`` into the Container under ``/export/``. A ``startup.sh`` script, that is usually starting Apache, PostgreSQL and Galaxy, will recognize the export directory with one of the following outcomes: @@ -47,7 +53,10 @@ Enabling Interactive Environments in Galaxy Interactive Environments (IE) are sophisticated ways to extend Galaxy with powerful services, like IPython, in a secure and reproducible way. For this we need to be able to launch Docker containers inside our Galaxy Docker container. At least docker 1.3 is needed on the host system. -``docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` + ```bash + docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true \ + -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable + ``` The port 8800 is the proxy port that is used to handle Interactive Environments. ``--privileged`` is needed to start docker containers inside docker. @@ -56,84 +65,148 @@ Using Parent docker On some linux distributions, Docker-In-Docker can run into issues (such as running out of loopback interfaces). If this is an issue, you can use a 'legacy' mode that use a docker socket for the parent docker installation mounted inside the container. To engage, set the environmental variable DOCKER_PARENT + + ```bash + docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true -e DOCKER_PARENT=True \ + -v /var/run/docker.sock:/var/run/docker.sock -v /home/user/galaxy_storage/:/export/ \ + bgruening/galaxy-stable + ``` -``docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true -e DOCKER_PARENT=True -v /var/run/docker.sock:/var/run/docker.sock -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` +Galaxy Report Webapp +-------------------- -Enabling the Galaxy Report Webapp ---------------------------------- +For admins wishing to have more information on the status of a galaxy instance, the Galaxy Report Webapp is served on `http://localhost:8080/reports`. As default this site is password protected with `admin:admin`. You can change this by providing a `reports_htpasswd` file in `/home/user/galaxy_storage/`. -For admins wishing to have more information on the status of a galaxy instance, you can start this image with ``-p 9003:9003`` to serve the Galaxy Report Webapp -on port 9003 on your host system. +You can disable the Report Webapp entirely by providing the environment variable `NONUSE` during container startup. -``docker run -d -p 8080:80 -p 8021:21 -p 9003:9003 -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable`` + ```bash + docker run -p 8080:80 -e "NONUSE=reports" bgruening/galaxy-stable + ``` +Galaxy's config settings +------------------------ + +Every Galaxy configuration setting can be overwritten by a given environment variable during startup. For example by default the `admin_users`, `master_api_key` and the `brand` variable it set to: + + ```sh + GALAXY_CONFIG_ADMIN_USERS=admin@galaxy.org + GALAXY_CONFIG_MASTER_API_KEY=HSNiugRFvgT574F43jZ7N9F3 + GALAXY_CONFIG_BRAND="Galaxy Docker Build" + ``` + +You can and should overwrite these during launching your container: + + ```bash + docker run -p 8080:80 \ + -e "GALAXY_CONFIG_ADMIN_USERS=albert@einstein.gov" \ + -e "GALAXY_CONFIG_MASTER_API_KEY=83D4jaba7330aDKHkakjGa937" \ + -e "GALAXY_CONFIG_BRAND='My own Galaxy flavour'" \ + bgruening/galaxy-stable + ``` + +Personalize your Galaxy +----------------------- + +The Galaxy welcome screen can be changed by providing a `welcome.hml` page in `/home/user/galaxy_storage/`. All files starting with `welcome` will be copied during starup and served as indroduction page. If you want to include images or other media, name them `welcome_*` and link them relative to your `welcome.html` ([example](`https://github.com/bgruening/docker-galaxy-stable/blob/master/galaxy/welcome.html`)). + + +Deactivating services +--------------------- + +Non-essential services can be deactivated during startup. Set the environment variable `NONUSE` to a comma separated list of services. Currently, `nodejs`, `proftp` and `reports` are supported. + + ```bash + docker run -d -p 8080:80 -p 8021:21 -p 9002:9002 \ + -e "NONUSE=nodejs,proftp,reports" bgruening/galaxy-stable + ``` Restarting Galaxy ----------------- If you want to restart Galaxy without restarting the entire Galaxy container we can use `docker exec` (docker > 1.3). -```docker exec supervisorctl restart galaxy:``` + ```sh + docker exec supervisorctl restart galaxy: + ``` In addition you start/stop every supersisord process using a webinterface on port `9002`. Start your container with: -``docker run -p 9002:9002 bgruening/galaxy-stable`` - + ```sh + docker run -p 9002:9002 bgruening/galaxy-stable + ``` Advanced Logging ---------------- You can set the environment variable $GALAXY_LOGGING to FULL to access all logs from supervisor. For example start your container with: -``docker run -d -p 8080:80 -p 8021:21 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable`` + ```sh + docker run -d -p 8080:80 -p 8021:21 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable + ``` In addition you can access the supersisord webinterface on port 9002 and get access to log files. Start your container with: -``docker run -d -p 8080:80 -p 8021:21 -p 9002:9002 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable`` - + ```sh + docker run -d -p 8080:80 -p 8021:21 -p 9002:9002 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable + ``` Extending the Docker Image ========================== -If you have your Tools already included in the Tool Shed, building your own personalised Galaxy docker Image can be done using the following steps: +If your tools are already included in the Tool Shed, building your own personalised Galaxy docker Image (Galaxy flavour) can be done using the following steps: 1. Create a file the name ``Dockerfile`` 2. Include ``FROM bgruening/galaxy-stable`` at the top of the file. This means that you use the Galaxy Docker Image as base Image and build your own extensions on top of it. 3. Install your Tools from the Tool Shed via the ``install_tool_shed_repositories.py`` script. 4. execute ``docker build -t='my-docker-test'`` - 5. run your container with ``docker run -d -p 8080:80 my-docker-test`` + 5. run your container with ``docker run -p 8080:80 my-docker-test`` 6. open your web browser on ``http://localhost:8080`` For example have a look at the [deepTools](http://deeptools.github.io/) or the [ChemicalToolBox](https://github.com/bgruening/galaxytools/tree/master/chemicaltoolbox) Dockerfile's. - -https://github.com/bgruening/docker-recipes/blob/master/galaxy-deeptools/Dockerfile -https://github.com/bgruening/docker-recipes/blob/master/galaxy-chemicaltoolbox/Dockerfile + * https://github.com/bgruening/docker-recipes/blob/master/galaxy-deeptools/Dockerfile + * https://github.com/bgruening/docker-recipes/blob/master/galaxy-chemicaltoolbox/Dockerfile ``` # Galaxy - deepTools # -# VERSION 0.1 +# VERSION 0.2 FROM bgruening/galaxy-stable MAINTAINER Björn A. Grüning, bjoern.gruening@gmail.com +ENV GALAXY_CONFIG_BRAND deepTools + WORKDIR /galaxy-central -RUN service postgresql start && service apache2 start && ./run.sh --daemon && sleep 120 && python ./scripts/api/install_tool_shed_repositories.py --api admin -l http://localhost:8080 --url -# Mark one folders as imported from the host. -VOLUME ["/export/"] +# Install deepTools +RUN install-repository \ + "--url https://toolshed.g2.bx.psu.edu/ -o bgruening --name deeptools" -# Expose port 80 to the host +# Mark folders as imported from the host. +VOLUME ["/export/", "/data/", "/var/lib/docker"] + +# Expose port 80 (webserver), 21 (FTP server), 8800 (Proxy) EXPOSE :80 +EXPOSE :21 +EXPOSE :8800 # Autostart script that is invoked during container start CMD ["/usr/bin/startup"] ``` +List of Galaxy flavours +----------------------- + + * [docker-galaxy-blast](https://github.com/bgruening/docker-galaxy-blast) + * [ChemicalToolBox](https://github.com/bgruening/docker-recipes/blob/master/galaxy-chemicaltoolbox) + * [ballaxy](https://github.com/anhi/docker-scripts/tree/master/ballaxy) + * [docker-galaxy-deeptools](https://github.com/bgruening/docker-recipes/blob/master/galaxy-deeptools) + * [docker-galaxyp](https://github.com/bgruening/docker-galaxyp) + Users & Passwords -================ +----------------- The Galaxy Admin User has the username ``admin@galaxy.org`` and the password ``admin``. The PostgreSQL username is ``galaxy``, the password is ``galaxy`` and the database name is ``galaxy`` (I know I was really creative ;)). @@ -142,9 +215,11 @@ If you want to create new users, please make sure to use the ``/export/`` volume The proftpd server is configured to use the main galaxy PostgreSQL user to access the database and select the username and password. If you want to run the docker container in production, please do not forget to change the user credentials in /etc/proftp/proftpd.conf too. +The Galaxy Report Webapp is `htpasswd` protected with username and password st to `admin`. + Development -=========== +----------- This repository uses a git submodule to include [Ansible roles](https://github.com/galaxyproject/ansible-galaxy-extras) maintained by the Galaxy project. @@ -160,16 +235,14 @@ Updating already existing submodules is possible with: git submodule update --remote ``` - Requirements -============ +------------ - [docker](https://www.docker.io/gettingstarted/#h_installation) - History -======= +------- - 0.1: Initial release! - with Apache2, PostgreSQL and Tool Shed integration @@ -186,7 +259,7 @@ History Support & Bug Reports -===================== +--------------------- -You can file an issue here https://github.com/bgruening/galaxy_recipes/issues or ask -us on the Galaxy development list http://lists.bx.psu.edu/listinfo/galaxy-dev +You can file an [github issue](https://github.com/bgruening/docker-galaxy-stable/issues) or ask +us on the [Galaxy development list](http://lists.bx.psu.edu/listinfo/galaxy-dev). From 845ed46e0d753223308685245d68218e01c940d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 7 Mar 2015 15:28:49 +0100 Subject: [PATCH 56/71] Update README.md --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index df8fb2172..44ebc14f5 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ For this we need to be able to launch Docker containers inside our Galaxy Docker ```bash docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true \ - -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable + -v /home/user/galaxy_storage/:/export/ bgruening/galaxy-stable ``` The port 8800 is the proxy port that is used to handle Interactive Environments. ``--privileged`` is needed to start docker containers inside docker. @@ -68,8 +68,8 @@ environmental variable DOCKER_PARENT ```bash docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true -e DOCKER_PARENT=True \ - -v /var/run/docker.sock:/var/run/docker.sock -v /home/user/galaxy_storage/:/export/ \ - bgruening/galaxy-stable + -v /var/run/docker.sock:/var/run/docker.sock -v /home/user/galaxy_storage/:/export/ \ + bgruening/galaxy-stable ``` Galaxy Report Webapp @@ -117,7 +117,7 @@ Non-essential services can be deactivated during startup. Set the environment va ```bash docker run -d -p 8080:80 -p 8021:21 -p 9002:9002 \ - -e "NONUSE=nodejs,proftp,reports" bgruening/galaxy-stable + -e "NONUSE=nodejs,proftp,reports" bgruening/galaxy-stable ``` Restarting Galaxy @@ -225,15 +225,15 @@ This repository uses a git submodule to include [Ansible roles](https://github.c You can clone this repository and the Ansible submodule with: -``` -git clone --recursive https://github.com/bgruening/docker-galaxy-stable.git -``` + ```sh + git clone --recursive https://github.com/bgruening/docker-galaxy-stable.git + ``` Updating already existing submodules is possible with: -``` -git submodule update --remote -``` + ```sh + git submodule update --remote + ``` Requirements ------------ From 5e2eb8530a0c0ae32de39c70f4c7005240dfa78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 7 Mar 2015 17:30:29 +0100 Subject: [PATCH 57/71] Fix Docker installation link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 44ebc14f5..c39deaca9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The Image is based on [Ubuntu 14.04 LTS](http://releases.ubuntu.com/14.04/) and Usage ===== -At first you need to install docker. Please follow the [very good instructions](https://www.docker.io/gettingstarted/#h_installation) from the Docker project. +At first you need to install docker. Please follow the [very good instructions](https://docs.docker.com/installation/) from the Docker project. After the successful installation, all what you need to do is: From 903d1548eaa574e309641135280977cd03c04a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 7 Mar 2015 17:47:38 +0100 Subject: [PATCH 58/71] Update README.md document the new supervisord webinterface --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c39deaca9..fa54746cf 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,9 @@ Non-essential services can be deactivated during startup. Set the environment va -e "NONUSE=nodejs,proftp,reports" bgruening/galaxy-stable ``` +A graphical user interface, to start and stop your services, is available on port 9002 if you run your container like above. + + Restarting Galaxy ----------------- From 8b51193b690f772f3f6f54d9cea53940a639a935 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 7 Mar 2015 17:50:46 +0100 Subject: [PATCH 59/71] add reports_wsgi.ini.sample file from the Galaxy dev branch. We need this file for the moment, because it will not be in next-stable. --- galaxy/reports_wsgi.ini.sample | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 galaxy/reports_wsgi.ini.sample diff --git a/galaxy/reports_wsgi.ini.sample b/galaxy/reports_wsgi.ini.sample new file mode 100644 index 000000000..8bac450a0 --- /dev/null +++ b/galaxy/reports_wsgi.ini.sample @@ -0,0 +1,100 @@ +# ---- HTTP Server ---------------------------------------------------------- + +[server:main] + +use = egg:Paste#http +port = 9001 +host = 127.0.0.1 +use_threadpool = true +threadpool_workers = 10 + +# ---- Filters -------------------------------------------------------------- + +# Filters sit between Galaxy and the HTTP server. + +# These filters are disabled by default. They can be enabled with +# 'filter-with' in the [app:main] section below. + +# Define the proxy-prefix filter. +[filter:proxy-prefix] +use = egg:PasteDeploy#prefix +prefix = /reports + +# ---- Galaxy Webapps Report Interface ------------------------------------------------- + +[app:main] + +# -- Application and filtering + +# If running behind a proxy server and Galaxy is served from a subdirectory, +# enable the proxy-prefix filter and set the prefix in the +# [filter:proxy-prefix] section above. +filter-with = proxy-prefix + +# If proxy-prefix is enabled and you're running more than one Galaxy instance +# behind one hostname, you will want to set this to the same path as the prefix +# in the filter above. This value becomes the "path" attribute set in the +# cookie so the cookies from each instance will not clobber each other. +#cookie_path = None + +# -- Report + +# Specifies the factory for the universe WSGI application +paste.app_factory = galaxy.webapps.reports.buildapp:app_factory +log_level = DEBUG + +# Database connection +# Galaxy reports are intended for production Galaxy instances, so sqlite is not supported. +# You may use a SQLAlchemy connection string to specify an external database. +# database_connection = postgres:///galaxy_test?user=postgres&password=postgres + +# Where dataset files are saved +#file_path = database/files +# Temporary storage for additional datasets, this should be shared through the cluster +#new_file_path = database/tmp + +# Mako templates are compiled as needed and cached for reuse, this directory is +# used for the cache +#template_cache_path = database/compiled_templates/reports + +# Session support (beaker) +use_beaker_session = True +session_type = memory +session_data_dir = %(here)s/database/beaker_sessions +session_key = galaxysessions +session_secret = changethisinproduction + +# Configuration for debugging middleware +# debug = true +use_lint = false + +# NEVER enable this on a public site (even test or QA) +# use_interactive = true + +# path to sendmail +sendmail_path = /usr/sbin/sendmail + +# Address to join mailing list +mailing_join_addr = galaxy-user-join@bx.psu.edu + +# Write thread status periodically to 'heartbeat.log' (careful, uses disk space rapidly!) +## use_heartbeat = True + +# Profiling middleware (cProfile based) +## use_profile = True + +# Mail +# smtp_server = yourserver@yourfacility.edu +# error_email_to = your_bugs@bx.psu.edu + +# Use the new iframe / javascript based layout +use_new_layout = true + +# Serving static files (needed if running standalone) +# static_enabled = True +# static_cache_time = 360 +# static_dir = %(here)s/static/ +# static_images_dir = %(here)s/static/images +# static_favicon_dir = %(here)s/static/favicon.ico +# static_scripts_dir = %(here)s/static/scripts/ +# static_style_dir = %(here)s/static/june_2007_style/blue From c310fcc403ef477bc968906483aa34bc8c81dffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 7 Mar 2015 18:28:55 +0100 Subject: [PATCH 60/71] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa54746cf..2e3592243 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,10 @@ you can use a 'legacy' mode that use a docker socket for the parent docker insta environmental variable DOCKER_PARENT ```bash - docker run -d -p 8080:80 -p 8021:21 -p 8800:8800 --privileged=true -e DOCKER_PARENT=True \ - -v /var/run/docker.sock:/var/run/docker.sock -v /home/user/galaxy_storage/:/export/ \ + docker run -p 8080:80 -p 8021:21 -p 8800:8800 \ + --privileged=true -e DOCKER_PARENT=True \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /home/user/galaxy_storage/:/export/ \ bgruening/galaxy-stable ``` From 4863268bbe638022760577769fc529999050a0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 7 Mar 2015 18:32:14 +0100 Subject: [PATCH 61/71] Update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 2e3592243..31d73340f 100644 --- a/README.md +++ b/README.md @@ -62,9 +62,7 @@ The port 8800 is the proxy port that is used to handle Interactive Environments. Using Parent docker ------------------- -On some linux distributions, Docker-In-Docker can run into issues (such as running out of loopback interfaces). If this is an issue, -you can use a 'legacy' mode that use a docker socket for the parent docker installation mounted inside the container. To engage, set the -environmental variable DOCKER_PARENT +On some linux distributions, Docker-In-Docker can run into issues (such as running out of loopback interfaces). If this is an issue, you can use a 'legacy' mode that use a docker socket for the parent docker installation mounted inside the container. To engage, set the environmental variable `DOCKER_PARENT` ```bash docker run -p 8080:80 -p 8021:21 -p 8800:8800 \ @@ -122,7 +120,7 @@ Non-essential services can be deactivated during startup. Set the environment va -e "NONUSE=nodejs,proftp,reports" bgruening/galaxy-stable ``` -A graphical user interface, to start and stop your services, is available on port 9002 if you run your container like above. +A graphical user interface, to start and stop your services, is available on port `9002` if you run your container like above. Restarting Galaxy @@ -149,7 +147,7 @@ You can set the environment variable $GALAXY_LOGGING to FULL to access all logs docker run -d -p 8080:80 -p 8021:21 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable ``` -In addition you can access the supersisord webinterface on port 9002 and get access to log files. Start your container with: +In addition you can access the supersisord webinterface on port `9002` and get access to log files. Start your container with: ```sh docker run -d -p 8080:80 -p 8021:21 -p 9002:9002 -e "GALAXY_LOGGING=full" bgruening/galaxy-stable From e00b94fea5d143e01f702895a4000ae97c11292f Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Tue, 10 Mar 2015 08:46:22 +0100 Subject: [PATCH 62/71] track new Galaxy stable release --- galaxy/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index 0c3d9110d..ee91221f2 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -24,7 +24,7 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo apt-get purge -y software-properties-common && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -ENV GALAXY_RELEASE=dev \ +ENV GALAXY_RELEASE=v15.03 \ GALAXY_ROOT=/galaxy-central \ GALAXY_CONFIG_DIR=/etc/galaxy From 90cf81f7ef020cf0f50d718262dfb1b927cd3d95 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 5 Mar 2015 09:51:09 -0500 Subject: [PATCH 63/71] Target my release_15.03_docker branch. It will be release_15.03 plus specific back-ported patches aimed at improving Docker experience. In particular - starting with greater dynamism in job_conf.xml (https://github.com/jmchilton/galaxy/commit/76fe8f25457baed16279b6d226f2828a3ed4ca34). --- galaxy/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index ee91221f2..bffc6d038 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -24,7 +24,8 @@ RUN apt-get -qq update && apt-get install --no-install-recommends -y apt-transpo apt-get purge -y software-properties-common && \ apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -ENV GALAXY_RELEASE=v15.03 \ +ENV GALAXY_RELEASE=release_15.03_docker \ +GALAXY_REPO=https://github.com/jmchilton/galaxy/ \ GALAXY_ROOT=/galaxy-central \ GALAXY_CONFIG_DIR=/etc/galaxy @@ -47,7 +48,7 @@ RUN groupadd -r $GALAXY_USER -g $GALAXY_GID && \ gpasswd -a $GALAXY_USER docker # Download latest stable release of Galaxy. -RUN mkdir $GALAXY_ROOT && wget -q -O - https://github.com/galaxyproject/galaxy/archive/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_ROOT +RUN mkdir $GALAXY_ROOT && wget -q -O - $GALAXY_REPO/archive/$GALAXY_RELEASE.tar.gz | tar xzf - --strip-components=1 -C $GALAXY_ROOT && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_ROOT # TODO: ensure virtualenv as part of galaxy role RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" From 39914c97e3b3a97fcdd69d13181bbc90638ad6b8 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 5 Mar 2015 09:57:56 -0500 Subject: [PATCH 64/71] PEP-8 fixes for export_user_files.py. --- galaxy/export_user_files.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index 4abdf7ceb..34633f043 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -10,6 +10,7 @@ PG_DATA_DIR_HOST = os.environ.get("PG_DATA_DIR_HOST", "/export/postgresql/9.3/main/") PG_CONF = '/etc/postgresql/9.3/main/postgresql.conf' + def change_path( src ): """ src will be copied to /export/`src` and a symlink will be placed in src pointing to /export/ @@ -81,7 +82,7 @@ def change_path( src ): # copy the postgresql data folder to the new location subprocess.call('cp -R %s/* %s' % (PG_DATA_DIR_DEFAULT, PG_DATA_DIR_HOST), shell=True) # copytree needs an non-existing dst dir, how annoying :( - #shutil.copytree(PG_DATA_DIR_DEFAULT, PG_DATA_DIR_HOST) + # shutil.copytree(PG_DATA_DIR_DEFAULT, PG_DATA_DIR_HOST) subprocess.call('chown -R postgres:postgres /export/postgresql/', shell=True) subprocess.call('chmod -R 0755 /export/', shell=True) subprocess.call('chmod -R 0700 %s' % PG_DATA_DIR_HOST, shell=True) @@ -91,4 +92,3 @@ def change_path( src ): new_data_directory = "'%s'" % PG_DATA_DIR_HOST cmd = 'sed -i "s|data_directory = .*|data_directory = %s|g" %s' % (new_data_directory, PG_CONF) subprocess.call(cmd, shell=True) - From 7ce2f3633fbcc67237614e1697ae36ad11240ce4 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 5 Mar 2015 10:04:19 -0500 Subject: [PATCH 65/71] Use modified configs (galaxy.ini/job_conf.xml) in in /export. Resolves #42. --- galaxy/export_user_files.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index 34633f043..b7e31072c 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -47,6 +47,7 @@ def change_path( src ): shutil.rmtree( '/export/.distribution_config/' ) shutil.copytree( '/galaxy-central/config/', '/export/.distribution_config/' ) + # Copy all files starting with "welcome" # This enables a flexible start page design. for filename in os.listdir('/export/'): @@ -55,6 +56,12 @@ def change_path( src ): image_file = os.path.join('/etc/galaxy/', filename) shutil.copy(export_file, image_file) + for config in [ 'galaxy.ini', 'job_conf.xml' ]: + export_config = os.path.join( '/export/galaxy-central/config', config ) + if os.path.exists(export_config): + image_config = os.path.join('/etc/galaxy/', config) + shutil.copy(export_config, image_config) + if not os.path.exists( '/export/galaxy-central/' ): os.makedirs("/export/galaxy-central/") os.chown( "/export/galaxy-central/", int(os.environ['GALAXY_UID']), int(os.environ['GALAXY_GID']) ) From 438716b47a73455606003ed7898bd50617584534 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Fri, 13 Mar 2015 09:57:34 -0400 Subject: [PATCH 66/71] Another shot at #42. --- galaxy/export_user_files.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index b7e31072c..f5151c77b 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -56,16 +56,24 @@ def change_path( src ): image_file = os.path.join('/etc/galaxy/', filename) shutil.copy(export_file, image_file) - for config in [ 'galaxy.ini', 'job_conf.xml' ]: - export_config = os.path.join( '/export/galaxy-central/config', config ) - if os.path.exists(export_config): - image_config = os.path.join('/etc/galaxy/', config) - shutil.copy(export_config, image_config) - if not os.path.exists( '/export/galaxy-central/' ): os.makedirs("/export/galaxy-central/") os.chown( "/export/galaxy-central/", int(os.environ['GALAXY_UID']), int(os.environ['GALAXY_GID']) ) + change_path('/galaxy-central/config/') + + # copy image defaults to config/.docker_sample to base derivatives on, + # and if there is a realized version of these files in the export directory + # replace Galaxy's copy with these. Use symbolic link instead of copying so + # deployer can update and reload Galaxy and changes will be reflected. + for config in [ 'galaxy.ini', 'job_conf.xml' ]: + image_config = os.path.join('/etc/galaxy/', config) + export_config = os.path.join( '/export/galaxy-central/config', config ) + export_sample = export_config + ".docker_sample" + shutil.copy(image_config, export_sample) + if os.path.exists(export_config): + subprocess.call('ln -s -f %s %s' % (export_config, image_config), shell=True) + change_path('/galaxy-central/integrated_tool_panel.xml') change_path('/galaxy-central/display_applications/') change_path('/galaxy-central/tool_deps/') From 9b832a9b6ea0ae488beb5f381c2cd1650c5d8d97 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 21 Mar 2015 18:23:37 +0100 Subject: [PATCH 67/71] Welcome page will be stored in /etc/galaxy/web/ --- galaxy/Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/galaxy/Dockerfile b/galaxy/Dockerfile index bffc6d038..e75401ffc 100644 --- a/galaxy/Dockerfile +++ b/galaxy/Dockerfile @@ -54,7 +54,7 @@ RUN mkdir $GALAXY_ROOT && wget -q -O - $GALAXY_REPO/archive/$GALAXY_RELEASE.tar. RUN su $GALAXY_USER -c "virtualenv $GALAXY_VIRTUALENV" # Setup Galaxy configuration files. -RUN mkdir -p $GALAXY_CONFIG_DIR && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CONFIG_DIR +RUN mkdir -p $GALAXY_CONFIG_DIR $GALAXY_CONFIG_DIR/web && chown -R $GALAXY_USER:$GALAXY_USER $GALAXY_CONFIG_DIR RUN su $GALAXY_USER -c "cp $GALAXY_ROOT/config/galaxy.ini.sample $GALAXY_CONFIG_FILE" ADD ./reports_wsgi.ini.sample $GALAXY_CONFIG_DIR/reports_wsgi.ini @@ -118,7 +118,7 @@ GALAXY_CONFIG_TOOLFORM_UPGRADE=True \ GALAXY_CONFIG_GALAXY_INFRASTRUCTURE_URL=http://$HOST_IP/ \ GALAXY_CONFIG_SANITIZE_ALL_HTML=False \ GALAXY_CONFIG_TOOLFORM_UPGRADE=True \ -GALAXY_CONFIG_WELCOME_URL=$GALAXY_CONFIG_DIR/welcome.html \ +GALAXY_CONFIG_WELCOME_URL=$GALAXY_CONFIG_DIR/web/welcome.html \ GALAXY_CONFIG_OVERRIDE_DEBUG=False # Define the default postgresql database path @@ -130,8 +130,8 @@ PG_DATA_DIR_HOST=/export/postgresql/9.3/main/ RUN cd /galaxy-central/lib/galaxy/web/proxy/js && npm install # Container Style -ADD GalaxyDocker.png $GALAXY_CONFIG_DIR/welcome_image.png -ADD welcome.html $GALAXY_CONFIG_DIR/welcome.html +ADD GalaxyDocker.png $GALAXY_CONFIG_DIR/web/welcome_image.png +ADD welcome.html $GALAXY_CONFIG_DIR/web/welcome.html # Switch back to User root USER root From 36aadc4eaf8839a08e61a610ed9f83a17867f568 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 21 Mar 2015 18:24:09 +0100 Subject: [PATCH 68/71] copy welcome files to /etc/galaxy/web/ --- galaxy/export_user_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/export_user_files.py b/galaxy/export_user_files.py index f5151c77b..436b37141 100644 --- a/galaxy/export_user_files.py +++ b/galaxy/export_user_files.py @@ -53,7 +53,7 @@ def change_path( src ): for filename in os.listdir('/export/'): if filename.startswith('welcome'): export_file = os.path.join( '/export/', filename) - image_file = os.path.join('/etc/galaxy/', filename) + image_file = os.path.join('/etc/galaxy/web/', filename) shutil.copy(export_file, image_file) if not os.path.exists( '/export/galaxy-central/' ): From 6981e5729238086274159830a85ef4b139c7a0fa Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Sat, 21 Mar 2015 18:24:41 +0100 Subject: [PATCH 69/71] Documentation fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 31d73340f..d7441d070 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ A graphical user interface, to start and stop your services, is available on por Restarting Galaxy ----------------- -If you want to restart Galaxy without restarting the entire Galaxy container we can use `docker exec` (docker > 1.3). +If you want to restart Galaxy without restarting the entire Galaxy container you can use `docker exec` (docker > 1.3). ```sh docker exec supervisorctl restart galaxy: From 12061e4d746836661174e40dbd646b892d26538e Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Mon, 23 Mar 2015 18:42:31 +0100 Subject: [PATCH 70/71] update ansible role --- galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index 7fd21bc87..41155d9a1 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit 7fd21bc876ab0335eff4511018e9a96e80be0ef4 +Subproject commit 41155d9a168f177f951a61a2723480bc5b196ab9 From 5f004306b3d89712585a77f31272a188827b9d90 Mon Sep 17 00:00:00 2001 From: Bjoern Gruening Date: Mon, 23 Mar 2015 19:48:26 +0100 Subject: [PATCH 71/71] update ansible role --- galaxy/roles/galaxyprojectdotorg.galaxyextras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/roles/galaxyprojectdotorg.galaxyextras b/galaxy/roles/galaxyprojectdotorg.galaxyextras index 41155d9a1..056e26452 160000 --- a/galaxy/roles/galaxyprojectdotorg.galaxyextras +++ b/galaxy/roles/galaxyprojectdotorg.galaxyextras @@ -1 +1 @@ -Subproject commit 41155d9a168f177f951a61a2723480bc5b196ab9 +Subproject commit 056e26452f9733be46f3f2f6cb67cb36e9c81b09