Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
551 lines (472 sloc) 24.9 KB
Adapted from Enis Afgan's mi-deployment code:
import os
import contextlib
from fabric.api import sudo, cd, settings, hide
from fabric.colors import red
from cloudbio.custom.shared import (_write_to_file, _setup_conf_file,
_setup_simple_service, _make_tmp_dir,
from import _install_tools
from cloudbio.galaxy.utils import _chown_galaxy, _read_boolean, _dir_is_empty
# -- Adjust this link if using content from another location
def _setup_users(env):
def _add_user(username, uid=None):
""" Add user with username to the system """
if not env.safe_contains('/etc/passwd', "%s:" % username):
uid_str = "--uid %s" % uid if uid else ""
env.safe_sudo('useradd -d /home/%s --create-home --shell /bin/bash '
'-c"Galaxy-required user" %s --user-group %s' %
(username, uid_str, username))
env.logger.debug("Done setting up Galaxy/CloudMan users")
def _setup_galaxy_env_defaults(env):
if "galaxy_user" not in env:
env.galaxy_user = "galaxy"
if "galaxy_home" not in env:
env.galaxy_home = "/mnt/galaxy/galaxy-app"
if "galaxy_tools_dir" not in env:
# Was called install_dir in
env.galaxy_tools_dir = "/mnt/galaxy/tools"
if "galaxy_loc_files" not in env:
indicies_dir = env.get("data_files", "/mnt/galaxyIndices")
env.galaxy_loc_files = os.path.join(indicies_dir, "galaxy", "galaxy-data")
if "galaxy_jars_dir" not in env:
env.galaxy_jars_dir = os.path.join(env.galaxy_home, "tool-data", "shared", "jars")
if "galaxy_update_default" not in env:
env.galaxy_update_default = True
if "python_version" not in env:
env.python_version = "2.7" # Override in fabricrc if this is not the case.
if "galaxy_indices_mount" not in env:
indicies_dir = env.get("data_files", "/mnt/galaxyIndices")
env.galaxy_indices_mount = indicies_dir
if "galaxy_data_mount" not in env:
env.galaxy_data_mount = "/mnt/galaxyData"
if "galaxy_init_database" not in env:
env.galaxy_init_database = False
if "galaxy_len_files" not in env:
env.galaxy_len_files = "/mnt/galaxy/configuration_data/len"
def _install_galaxy(env):
Used to install Galaxy and setup its environment, including tools.
This method is somewhat targeted for the cloud deployment so some
tweaking of the code may be desirable. This method cannot be used
to update an existing Galaxy.
_chown_galaxy(env, env.galaxy_home) # Make sure env.galaxy_user owns env.galaxy_home
env.safe_sudo("chmod 755 %s" % os.path.split(env.galaxy_home)[0])
setup_db = _read_boolean(env, "galaxy_setup_database", False)
if setup_db:
setup_service = _read_boolean(env, "galaxy_setup_service", False)
if setup_service:
setup_xvfb = _read_boolean(env, "galaxy_setup_xvfb", False)
if setup_xvfb:
_chown_galaxy(env, env.galaxy_home) # Make sure env.galaxy_user owns env.galaxy_home
_chown_galaxy(env, env.galaxy_loc_files) # Make sure env.galaxy_user owns env.galaxy_loc_files
return True
def _clone_galaxy_repo(env):
Clone Galaxy source code repository from ``env.galaxy_repository`` to
``env.galaxy_home``, setting the directory ownership to ``env.galaxy_user``
This method cannot be used to update an existing Galaxy installation.
# Make sure ``env.galaxy_home`` dir exists but without Galaxy in it
galaxy_exists = False
if env.safe_exists(env.galaxy_home):
if env.safe_exists(os.path.join(env.galaxy_home, '.hg')):
env.logger.warning("Galaxy install dir {0} exists and seems to have "
"a Mercurial repository already there. Galaxy already installed?"
galaxy_exists = True
env.safe_sudo("mkdir -p '%s'" % env.galaxy_home)
if not galaxy_exists:
with cd(env.galaxy_home):
# Needs to be done as non galaxy user, otherwise we have a
# permissions problem.
galaxy_repository = env.get("galaxy_repository", '')
env.safe_sudo('hg clone %s .' % galaxy_repository)
# Make sure ``env.galaxy_home`` is owned by ``env.galaxy_user``
_chown_galaxy(env, env.galaxy_home)
# Make sure env.galaxy_home root dir is also owned by env.galaxy_user so Galaxy
# process can create necessary dirs (e.g., shed_tools, tmp)
env.safe_sudo("chown {0}:{0} {1}".format(env.galaxy_user, os.path.split(env.galaxy_home)[0]))
# If needed, custom-configure this freshly cloned Galaxy
preconfigured = _read_boolean(env, "galaxy_preconfigured_repository", False)
if not preconfigured:
def _setup_galaxy_db(env):
Create (if one already does not exist) and initialize a database for use
by Galaxy.
if not _galaxy_db_exists(env):
def _get_galaxy_db_configs(env):
Extract configuration options for Galaxy database and return those as a dictionary
config = {}
config['psql_data_dir'] = env.get('galaxy_database_path', '/mnt/galaxy/db')
config['psql_conf_file'] = os.path.join(config['psql_data_dir'], 'postgresql.conf')
config['psql_bin_dir'] = env.get('postgres_bin_dir', '/usr/lib/postgresql/9.1/bin')
config['psql_user'] = env.get('postrges_user', 'postgres')
config['psql_port'] = env.get('postgres_port', '5910')
config['psql_log'] = '/tmp/pSQL.log'
config['galaxy_db_name'] = env.get('galaxy_db_name', 'galaxy')
config['galaxy_ftp_user_pwd'] = env.get('galaxy_ftp_user_password', 'fu5yOj2sn')
# And a couple of useful command shortcuts
config['pg_ctl_cmd'] = "{0} -D {2}".format(os.path.join(config['psql_bin_dir'], 'pg_ctl'),
config['psql_port'], config['psql_data_dir'])
config['pg_start_cmd'] = "{0} -w -l {1} start".format(config['pg_ctl_cmd'], config['psql_log'])
config['pg_stop_cmd'] = "{0} -w stop".format(config['pg_ctl_cmd'])
config['psql_cmd'] = "{0} -p {1}".format(os.path.join(config['psql_bin_dir'], 'psql'),
return config
def _galaxy_db_exists(env):
Check if galaxy database already exists. Return ``True`` if it does,
``False`` otherwise.
Note that this method does a best-effort attempt at starting the DB server
if one is not already running to do a thorough test. It shuts the server
down upon completion, but only it if also started it.
db_exists = False
started = False
c = _get_galaxy_db_configs(env)
if env.safe_exists(c['psql_data_dir']) and not _dir_is_empty(c['psql_data_dir']):
env.safe_sudo("chown --recursive {0}:{0} {1}".format(c['psql_user'], c['psql_data_dir']))
env.logger.debug("Galaxy database directory {0} already exists.".format(c['psql_data_dir']))
# Check if PostgreSQL is already running and try to start the DB if not
if not _postgres_running(env):
with settings(warn_only=True):
env.logger.debug("Trying to start DB server in {0}".format(c['psql_data_dir']))
env.safe_sudo("{0}".format(c['pg_start_cmd']), user=c['psql_user'])
started = True
# Check if galaxy DB already exists
if 'galaxy' in sudo("{0} -P pager --list | grep {1} || true".format(c['psql_cmd'],
c['galaxy_db_name']), user=c['psql_user']):
env.logger.warning("Galaxy database {0} already exists in {1}! Not creating it."
.format(c['galaxy_db_name'], c['psql_data_dir']))
db_exists = True
if started:
with settings(warn_only=True):
env.safe_sudo("{0}".format(c['pg_stop_cmd']), user=c['psql_user'])
return db_exists
def _create_galaxy_db(env):
Create a new PostgreSQL database for use by Galaxy
c = _get_galaxy_db_configs(env)
if not env.safe_exists(c['psql_data_dir']):
env.safe_sudo("mkdir -p {0}".format(c['psql_data_dir']))
env.safe_sudo("chown --recursive {0}:{0} {1}".format(c['psql_user'], c['psql_data_dir']))
# Initialize a new database for Galaxy in ``psql_data_dir``
if _dir_is_empty(c['psql_data_dir']):
env.safe_sudo("{0} -D {1}".format(os.path.join(c['psql_bin_dir'], 'initdb'), c['psql_data_dir']),
# Set port for the database server
env.safe_sed(c['psql_conf_file'], '#port = 5432', 'port = {0}'.format(c['psql_port']), use_sudo=True)
env.safe_sudo("chown {0}:{0} {1}".format(c['psql_user'], c['psql_conf_file']))
# Start PostgreSQL server so a role for Galaxy user can be created
if not _postgres_running(env):
env.safe_sudo(c['pg_start_cmd'], user=c['psql_user'])
started = True
# Restart is required so port setting takes effect
env.safe_sudo("{0} -D {1} -w -l {2} restart".format(c['pg_ctl_cmd']), c['psql_data_dir'],
c['psql_log'], user=c['psql_user'])
started = False
# Create a role for env.galaxy_user
env.safe_sudo('{0} -c"CREATE ROLE {1} LOGIN CREATEDB"'.format(c['psql_cmd'], env.galaxy_user),
# Create a Galaxy database
env.safe_sudo('{0} -p {1} {2}'.format(os.path.join(c['psql_bin_dir'], 'createdb'),
c['psql_port'], c['galaxy_db_name']), user=env.galaxy_user)
# Create a role for 'galaxyftp' user
env.safe_sudo('{0} -c"CREATE ROLE galaxyftp LOGIN PASSWORD \'{1}\'"'.format(c['psql_cmd'],
c['galaxy_ftp_user_pwd']), user=c['psql_user'])
if started:
with settings(warn_only=True):
env.safe_sudo("{0}".format(c['pg_stop_cmd']), user=c['psql_user'])
exp = "export PATH={0}:$PATH".format(c['psql_bin_dir'])
def _init_galaxy_db(env):
Initialize Galaxy's database with the tables and apply the migrations,
fetching Galaxy eggs in the process.
with cd(env.galaxy_home):
universe_wsgi_url = env.get('galaxy_universe_wsgi_url',
os.path.join(CM_REPO_ROOT_URL, ''))
env.safe_sudo("wget --output-document=universe_wsgi.ini {0}".format(universe_wsgi_url))
started = False
if not _postgres_running(env):
c = _get_galaxy_db_configs(env)
env.safe_sudo(c['pg_start_cmd'], user=c['psql_user'])
started = True
sudo("bash -c 'export PYTHON_EGG_CACHE=eggs; python -ES ./scripts/; ./'",
if started:
with settings(warn_only=True):
env.safe_sudo("{0}".format(c['pg_stop_cmd']), user=c['psql_user'])
def _configure_galaxy_options(env, option_dict=None, prefix="galaxy_universe_"):
Read through fabric's environment and make sure any property of
the form galaxy_universe_XXX=YYY lands up in Galaxy's universe_wsgi.ini
options as XXX=YYY using Galaxy configuration directory:
galaxy_conf_directory = env.get("galaxy_conf_directory", None)
if not galaxy_conf_directory:
return False
# By default just read the options from env (i.e. from fabricrc), but
# allow override so the options can come from a YAML file (such as done
# with galaxy-vm-launcher.)
if option_dict is None:
option_dict = env
option_priority = env.get("galaxy_conf_priority", "200")
for key, value in option_dict.iteritems():
if key.startswith(prefix):
key = key[len(prefix):]
conf_file_name = "%s_override_%s.ini" % (option_priority, key)
conf_file = os.path.join(galaxy_conf_directory, conf_file_name)
contents = "[app:main]\n%s=%s" % (key, value)
_write_to_file(contents, conf_file, 0700)
_chown_galaxy(env, conf_file)
def _setup_shed_tools_dir(env):
ts_dir = "%s/../shed_tools" % env.galaxy_home
if not env.safe_exists(ts_dir):
_make_dir_for_galaxy(env, ts_dir)"Setup Tool Shed directory {0}".format(ts_dir))
def _setup_trackster(env):
Download .len files required by Trackster:
if not env.safe_exists(env.galaxy_len_files):
env.safe_sudo("mkdir -p {0}".format(env.galaxy_len_files))
with cd(env.galaxy_len_files):
if not env.safe_exists(os.path.join(env.galaxy_len_files, "hg19.len")):
local_fn = "len-files.tar.gz"
env.safe_sudo('wget --output-document={0} '
env.safe_sudo("tar xzf {0}".format(local_fn))
env.safe_sudo("rm {0}".format(local_fn))
_chown_galaxy(env, env.galaxy_len_files)
def _configure_galaxy_repository(env):
Custom-configure Galaxy repository. This is primarily targeted at a cloud
mi-deployment would always edit the repository in this way, but
galaxy-vm-launcher requires the configured Galaxy repository to pull
in the changesets from
which prebakes these modifications in.
_chown_galaxy(env, env.galaxy_home) # Make sure env.galaxy_user owns env.galaxy_home
with cd(env.galaxy_home): # and settings(warn_only=True):
# Make sure Galaxy runs in a new shell and does not
# inherit the environment by adding the '-ES' flag
# to all invocations of python within
env.safe_sudo("sed -i 's/python .\//python -ES .\//g' %s/" % (env.galaxy_home), user=env.galaxy_user)
if _read_boolean(env, "galaxy_cloud", True):
# Append DRMAA_LIBRARY_PATH in as well (this file will exist
# once SGE is installed - which happens at instance contextualization)
env.safe_sudo("grep -q 'export DRMAA_LIBRARY_PATH=/opt/sge/lib/lx24-amd64/' %s/; if [ $? -eq 1 ]; then sed -i '2 a export DRMAA_LIBRARY_PATH=/opt/sge/lib/lx24-amd64/'; fi" % (env.galaxy_home), user=env.galaxy_user)
# Upload the custom cloud welcome screen files
if not env.safe_exists("%s/static/images/cloud.gif" % env.galaxy_home):
env.safe_sudo("wget --output-document=%s/static/images/cloud.gif %s/cloud.gif" % (env.galaxy_home, CDN_ROOT_URL), user=env.galaxy_user)
if not env.safe_exists("%s/static/images/cloud_txt.png" % env.galaxy_home):
env.safe_sudo("wget --output-document=%s/static/images/cloud_text.png %s/cloud_text.png" % (env.galaxy_home, CDN_ROOT_URL), user=env.galaxy_user)
env.safe_sudo("wget --output-document=%s/static/welcome.html %s/welcome.html" % (env.galaxy_home, CDN_ROOT_URL), user=env.galaxy_user)
# Set up the symlink for SAMTOOLS (remove this code once SAMTOOLS is converted to data tables)
if env.safe_exists("%s/tool-data/sam_fa_indices.loc" % env.galaxy_home):
env.safe_sudo("rm %s/tool-data/sam_fa_indices.loc" % env.galaxy_home, user=env.galaxy_user)
# TODO: Is this really necessary here? Shouldn't the tools do this themselves?
# set up the jars directory for Java tools
if not env.safe_exists(env.galaxy_jars_dir):
env.safe_sudo("mkdir -p %s" % env.galaxy_jars_dir, user=env.galaxy_user)
srma_dir = os.path.join(env.galaxy_tools_dir, 'srma', 'default')
haploview_dir = os.path.join(env.galaxy_tools_dir, 'haploview', 'default')
picard_dir = os.path.join(env.galaxy_tools_dir, 'picard', 'default')
env.safe_sudo('ln -s -f %s/srma.jar %s' % (srma_dir, env.galaxy_jars_dir), user=env.galaxy_user)
env.safe_sudo('ln -s -f %s/haploview.jar %s' % (haploview_dir, env.galaxy_jars_dir), user=env.galaxy_user)
env.safe_sudo('ln -s -f %s/*.jar %s' % (picard_dir, env.galaxy_jars_dir), user=env.galaxy_user)
return True
def _setup_service(env):
_setup_conf_file(env, "/etc/init.d/galaxy", "galaxy_init", default_source="galaxy_init")
_setup_conf_file(env, "/etc/default/galaxy", "galaxy_default")
def _setup_xvfb(env):
_setup_conf_file(env, "/etc/init.d/xvfb", "xvfb_init", default_source="xvfb_init")
_setup_conf_file(env, "/etc/default/xvfb", "xvfb_default", default_source="xvfb_default")
env.safe_sudo("mkdir /var/lib/xvfb; chown root:root /var/lib/xvfb; chmod 0755 /var/lib/xvfb")
display_export = "-v DISPLAY=:42"
_add_to_profiles(display_export, profiles=["/home/%s/.sge_request" % env.get("galaxy_user", "galaxy")])
def _setup_nginx_service(env):
# Setup system service for nginx, not needed for CloudMan but it is
# useful if CloudMan is not being used (such as galaxy-vm-launcher work).
_setup_conf_file(env, "/etc/init.d/nginx", "nginx_init", default_source="nginx_init")
def _install_nginx_standalone(env):
def _install_nginx_package(env):
Install nginx from a custom package; also see
version = "1.4.7-gvl20140507b01-precise"
package_url = "" % version
with _make_tmp_dir() as work_dir:
with contextlib.nested(cd(work_dir), settings(hide('stdout'))):
env.safe_run("wget %s" % package_url)
env.safe_sudo("dpkg -i %s" % os.path.split(package_url)[1])
# The path for `nginx.conf` depends on how the package was built and
# what's set in `nginx_remote_conf_path` must match that!
defaults = {"galaxy_home": "/mnt/galaxy/galaxy-app"}
_setup_conf_file(env, env.nginx_remote_conf_path, "nginx.conf", defaults=defaults)
env.logger.debug("Nginx v{0} installed from package {1}".format(version, package_url))
def _install_nginx(env):
"""Nginx open source web server.
if "use_nginx_package" in env and env.use_nginx_package.upper() in ["TRUE", "YES"]:
# Install nginx from directly
version = "1.3.8"
url = "" % version
install_dir = os.path.join(env.install_dir, "nginx")
remote_conf_dir = os.path.join(install_dir, "conf")
# Skip install if already present
if env.safe_exists(remote_conf_dir) and env.safe_contains(os.path.join(remote_conf_dir, "nginx.conf"), "/cloud"):
env.logger.debug("Nginx already installed; not installing it again.")
with _make_tmp_dir() as work_dir:
with contextlib.nested(cd(work_dir), settings(hide('stdout'))):
modules = _get_nginx_modules(env)
module_flags = " ".join(["--add-module=../%s" % x for x in modules])
env.safe_run("wget %s" % url)
env.safe_run("tar xvzf %s" % os.path.split(url)[1])
with cd("nginx-%s" % version):
env.safe_run("./configure --prefix=%s --with-ipv6 %s "
"--user=galaxy --group=galaxy --with-debug "
"--with-http_ssl_module --with-http_gzip_static_module " %
(install_dir, module_flags))
env.safe_sed("objs/Makefile", "-Werror", "")
env.safe_sudo("make install")
env.safe_sudo("cd %s; stow nginx" % env.install_dir)
defaults = {"galaxy_home": "/mnt/galaxy/galaxy-app"}
_setup_conf_file(env, os.path.join(remote_conf_dir, "nginx.conf"), "nginx.conf", defaults=defaults)
nginx_errdoc_file = 'nginx_errdoc.tar.gz'
url = os.path.join(REPO_ROOT_URL, nginx_errdoc_file)
remote_errdoc_dir = os.path.join(install_dir, "html")
with cd(remote_errdoc_dir):
env.safe_sudo("wget --output-document=%s/%s %s" % (remote_errdoc_dir, nginx_errdoc_file, url))
env.safe_sudo('tar xvzf %s' % nginx_errdoc_file)
env.safe_sudo("mkdir -p %s" % env.install_dir)
if not env.safe_exists("%s/nginx" % env.install_dir):
env.safe_sudo("ln -s %s/sbin/nginx %s/nginx" % (install_dir, env.install_dir))
# If the guessed symlinking did not work, force it now
cloudman_default_dir = "/opt/galaxy/sbin"
if not env.safe_exists(cloudman_default_dir):
env.safe_sudo("mkdir -p %s" % cloudman_default_dir)
if not env.safe_exists(os.path.join(cloudman_default_dir, "nginx")):
env.safe_sudo("ln -s %s/sbin/nginx %s/nginx" % (install_dir, cloudman_default_dir))
env.logger.debug("Nginx {0} installed to {1}".format(version, install_dir))
def _get_nginx_modules(env):
"""Retrieve add-on modules compiled along with nginx.
modules = {
"upload": True,
"chunk": True,
"ldap": False
module_dirs = []
for module, enabled_by_default in modules.iteritems():
enabled = _read_boolean(env, "nginx_enable_module_%s" % module, enabled_by_default)
if enabled:
module_dirs.append(eval("_get_nginx_module_%s" % module)(env))
return module_dirs
def _get_nginx_module_upload(env):
upload_module_version = "2.2.0"
upload_url = "" \
"nginx_upload_module-%s.tar.gz" % upload_module_version
env.safe_run("wget %s" % upload_url)
upload_fname = os.path.split(upload_url)[1]
env.safe_run("tar -xvzpf %s" % upload_fname)
return upload_fname.rsplit(".", 2)[0]
def _get_nginx_module_chunk(env):
chunk_module_version = "0.22"
chunk_git_version = "b46dd27"
chunk_url = "" % chunk_module_version
chunk_fname = "agentzh-chunkin-nginx-module-%s.tar.gz" % (chunk_git_version)
env.safe_run("wget -O %s %s" % (chunk_fname, chunk_url))
env.safe_run("tar -xvzpf %s" % chunk_fname)
return chunk_fname.rsplit(".", 2)[0]
def _get_nginx_module_ldap(env):
env.safe_run("rm -rf nginx-auth-ldap") # Delete it if its there or git won't clone
env.safe_run("git clone")
return "nginx-auth-ldap"
def _setup_postgresql(env):
# Handled by CloudMan, but if configuring standalone galaxy, this
# will need to be executed to create a postgres user for Galaxy.
def _configure_postgresql(env, delete_main_dbcluster=False):
""" This method is intended for cleaning up the installation when
PostgreSQL is installed from a package. Basically, when PostgreSQL
is installed from a package, it creates a default database cluster
and splits the config file away from the data.
This method can delete the default database cluster that was automatically
created when the package is installed. Deleting the main database cluster
also has the effect of stopping the auto-start of the postmaster server at
machine boot. The method adds all of the PostgreSQL commands to the PATH.
pg_ver = sudo("dpkg -s postgresql | grep Version | cut -f2 -d':'")
pg_ver = pg_ver.strip()[:3] # Get first 3 chars of the version since that's all that's used for dir name
got_ver = False
while(not got_ver):
pg_ver = float(pg_ver)
got_ver = True
except Exception:
print(red("Problems trying to figure out PostgreSQL version."))
pg_ver = raw_input(red("Enter the correct one (eg, 9.1; not 9.1.3): "))
if delete_main_dbcluster:
env.safe_sudo('pg_dropcluster --stop %s main' % pg_ver, user='postgres')
exp = "export PATH=/usr/lib/postgresql/%s/bin:$PATH" % pg_ver
if not env.safe_contains('/etc/bash.bashrc', exp):
env.safe_append('/etc/bash.bashrc', exp, use_sudo=True)
def _init_postgresql_data(env):
if "galaxy" not in env.safe_sudo("psql -P pager --list | grep galaxy || true", user="postgres"):
env.safe_sudo("createdb galaxy", user="postgres")
env.safe_sudo("psql -c 'create user galaxy; grant all privileges on database galaxy to galaxy;'", user="postgres")
def _postgres_running(env):
Return ``True`` if PostgreSQL is running, ``False`` otherwise.
c = _get_galaxy_db_configs(env)
if 'no server running' in sudo("{0} status || true".format(c['pg_ctl_cmd']), user=c['psql_user']):
return False
return True
def _make_dir_for_galaxy(env, path):
env.safe_sudo("mkdir -p '%s'" % path)
_chown_galaxy(env, path)