Merge remote-tracking branch 'upstream/dev' into hashtags

This commit is contained in:
Dannon Baker
2017-04-26 14:55:17 -04:00
22 changed files with 139 additions and 54 deletions
+6 -1
View File
@@ -1,3 +1,4 @@
sudo: false
language: python
python: 2.7
os:
@@ -24,9 +25,13 @@ matrix:
allow_failures:
- env: TOX_ENV=py27-lint-imports
addons:
apt:
packages:
- libxml2-utils
install:
- pip install tox
- if [ "$TOX_ENV" == "validate-test-tools" ]; then sudo apt-get install libxml2-utils; fi
- if [ "$TOX_ENV" == "qunit" ]; then bash -c 'cd test/qunit && npm install'; fi
- if [ "$TOX_ENV" == "first_startup" ]; then bash -c "bash scripts/common_startup.sh && wget -q https://github.com/jmchilton/galaxy-downloads/raw/master/db_gx_rev_0127.sqlite && mv db_gx_rev_0127.sqlite database/universe.sqlite && bash manage_db.sh -c ./config/galaxy.ini.sample upgrade"; fi
@@ -11,7 +11,7 @@ var Configurations = {
{ src: 'hdca', icon: 'fa-folder-o', tooltip: 'Dataset collection', multiple: false, batch: Batch.LINKED } ],
data_multiple: [
{ src: 'hda', icon: 'fa-files-o', tooltip: 'Multiple datasets', multiple: true, batch: Batch.DISABLED },
{ src: 'hdca', icon: 'fa-folder-o', tooltip: 'Dataset collection', multiple: false, batch: Batch.DISABLED } ],
{ src: 'hdca', icon: 'fa-folder-o', tooltip: 'Dataset collections', multiple: true, batch: Batch.DISABLED } ],
data_collection: [
{ src: 'hdca', icon: 'fa-folder-o', tooltip: 'Dataset collection', multiple: false, batch: Batch.DISABLED } ],
workflow_data: [
+5
View File
@@ -591,6 +591,11 @@ nglims_config_file = tool-data/nglims.yaml
# URL (with schema http/https) of the Galaxy instance as accessible within your
# local network - if specified used as a default by pulsar file staging and
# Jupyter Docker container for communicating back with Galaxy via the API.
#
# If you are attempting to setup GIEs on Mac OS X with Docker for Mac - this
# should likely be the IP address of your machine on the virtualbox network (vboxnet0)
# setup for the Docker host VM. This can found by running ifconfig and using the
# IP address of the network vboxnet0.
#galaxy_infrastructure_url = http://localhost:8080
# If the above URL cannot be determined ahead of time in dynamic environments
@@ -6,7 +6,7 @@
# appropriate `apt-get/pip install` statements.
---
-
image: erasche/docker-rstudio-notebook:16.10
image: erasche/docker-rstudio-notebook:17.01
description: |
If you've ever done R analysis, you probably used RStudio. This
familiar R analysis software suite will let you explore your datasets
@@ -20,7 +20,7 @@ password_auth = True
# The image argument was moved to "allowed_images.yml.sample"
# Additional arguments that are passed to the `docker run` command.
#command_inject = --sig-proxy=true -e DEBUG=false
#command_inject = --sig-proxy=true -e DEBUG=false -e DEFAULT_CONTAINER_RUNTIME=120
# URL to access the Galaxy API with from the spawn Docker containter, if empty
# this falls back to galaxy.ini's galaxy_infrastructure_url and finally to the
@@ -14,11 +14,11 @@ function message_failed_connection(){
* @param {String} notebook_access_url: the URL embeded in the page and loaded
*
*/
function load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url, username){
function load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url){
// Test notebook_login_url for accessibility, executing the login+load function whenever
// we've successfully connected to the IE.
test_ie_availability(notebook_pubkey_url, function(){
var payload = username + "\n" + ie_password;
var payload = "rstudio\nrstudio";
$.ajax({
type: 'GET',
url: notebook_pubkey_url,
@@ -32,7 +32,6 @@ function load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_
console.log("Found " + exp +" and " + mod);
var rsa = new RSAKey();
rsa.setPublic(mod, exp);
console.log("Encrypting '" + username + "', '" + ie_password + "'");
var enc_hex = rsa.encrypt(payload);
var encrypted = hex2b64(enc_hex);
console.log("E: " + encrypted);
@@ -58,7 +57,10 @@ function load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_
append_notebook(notebook_access_url);
},
error: function(jqxhr, status, error){
message_failed_connection();
// TODO: Uncomment when rstudio / nginx play nicely and
// don't return http when we asked for HTTPS, thereby
// issuing a mixed-content warning.
//message_failed_connection();
// Do we want to try and load the notebook anyway? Just in case?
append_notebook(notebook_access_url);
}
@@ -1,4 +1,5 @@
<%namespace file="ie.mako" name="ie"/>
<%namespace name="ie" file="ie.mako"/>
<%
import os
import shutil
@@ -7,46 +8,42 @@ import time
# Sets ID and sets up a lot of other variables
ie_request.load_deploy_config()
ie_request.attr.docker_port = 80
# Create tempdir in galaxy
temp_dir = ie_request.temp_dir
PASSWORD = "rstudio"
USERNAME = "rstudio"
# Then override it again
ie_request.notebook_pw = "rstudio"
# Did the user give us an RData file?
if hda.datatype.__class__.__name__ == "RData":
shutil.copy( hda.file_name, os.path.join(temp_dir, '.RData') )
DATASET_HID = hda.hid
# Add all environment variables collected from Galaxy's IE infrastructure
ie_request.launch(
image=trans.request.params.get('image_tag', None),
additional_ids=trans.request.params.get('additional_dataset_ids', None),
env_override={
'notebook_username': USERNAME,
'notebook_password': PASSWORD,
'dataset_hid': DATASET_HID,
}
)
## General IE specific
# Access URLs for the notebook from within galaxy.
# TODO: Make this work without pointing directly to IE. Currently does not work
# through proxy.
notebook_pubkey_url = ie_request.url_template('${PROXY_URL}/rstudio/auth-public-key')
notebook_access_url = ie_request.url_template('${PROXY_URL}/rstudio/')
notebook_login_url = ie_request.url_template('${PROXY_URL}/rstudio/auth-do-sign-in')
notebook_login_url = ie_request.url_template('${PROXY_URL}/rstudio/auth-do-sign-in')
notebook_pubkey_url = ie_request.url_template('${PROXY_URL}/rstudio/auth-public-key')
%>
<html>
<head>
${ ie.load_default_js() }
</head>
<body style="margin:0px">
<body style="margin: 0px">
<script type="text/javascript">
${ ie.default_javascript_variables() }
var notebook_login_url = '${ notebook_login_url }';
var notebook_access_url = '${ notebook_access_url }';
var notebook_pubkey_url = '${ notebook_pubkey_url }';
var notebook_username = '${ USERNAME }';
require.config({
baseUrl: app_root,
paths: {
@@ -65,11 +62,11 @@ requirejs([
'plugin/rstudio'
], function(){
load_when_ready(ie_readiness_url, function(){
load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url, "${ USERNAME }");
load_notebook(notebook_login_url, notebook_access_url, notebook_pubkey_url);
});
});
</script>
<div id="main">
<div id="main" width="100%" height="100%">
</div>
</body>
</html>
+8
View File
@@ -3512,6 +3512,14 @@ class DatasetCollectionElement( object, Dictifiable ):
else:
return element_object
@property
def dataset_instances( self ):
element_object = self.element_object
if isinstance( element_object, DatasetCollection ):
return element_object.dataset_instances
else:
return [element_object]
def copy_to_collection( self, collection, destination=None, element_destination=None ):
element_object = self.element_object
if element_destination:
+6 -3
View File
@@ -153,6 +153,8 @@ GALAXY_LIB_TOOLS_UNVERSIONED = [
# with the version at which they were fixed.
GALAXY_LIB_TOOLS_VERSIONED = {
"sam_to_bam": LooseVersion("1.1.3"),
"PEsortedSAM2readprofile": LooseVersion("1.1.1"),
"fetchflank": LooseVersion("1.0.1"),
}
@@ -2310,9 +2312,10 @@ class DatabaseOperationTool( Tool ):
for input_dataset in input_datasets.values():
check_dataset_instance( input_dataset )
for input_dataset_collection in input_dataset_collections.values():
if not input_dataset_collection.collection.populated:
raise ToolInputsNotReadyException()
for input_dataset_collection_pairs in input_dataset_collections.values():
for input_dataset_collection, is_mapped in input_dataset_collection_pairs:
if not input_dataset_collection.collection.populated:
raise ToolInputsNotReadyException()
map( check_dataset_instance, input_dataset_collection.dataset_instances )
+6 -2
View File
@@ -12,8 +12,12 @@ log = logging.getLogger( __name__ )
class ModelOperationToolAction( DefaultToolAction ):
def check_inputs_ready( self, tool, trans, incoming, history ):
history, inp_data, inp_dataset_collections = self._collect_inputs(tool, trans, incoming, history)
def check_inputs_ready( self, tool, trans, incoming, history, execution_cache=None ):
if execution_cache is None:
execution_cache = ToolExecutionCache(trans)
current_user_roles = execution_cache.current_user_roles
history, inp_data, inp_dataset_collections = self._collect_inputs(tool, trans, incoming, history, current_user_roles)
tool.check_inputs_ready( inp_data, inp_dataset_collections )
+1 -1
View File
@@ -48,7 +48,7 @@ def execute( trans, tool, param_combinations, history, rerun_remap_job_id=None,
burst_at = getattr( config, 'tool_submission_burst_at', 10 )
burst_threads = getattr( config, 'tool_submission_burst_threads', 1 )
tool_action = tool.action
tool_action = tool.tool_action
if hasattr( tool_action, "check_inputs_ready" ):
for params in execution_tracker.param_combinations:
# This will throw an exception if the tool is not ready.
@@ -6,7 +6,9 @@ import random
import stat
import tempfile
import uuid
from subprocess import PIPE, Popen
from sys import platform as _platform
import yaml
@@ -18,6 +20,8 @@ from galaxy.util import string_as_bool_or_none
from galaxy.util.bunch import Bunch
IS_OS_X = _platform == "darwin"
CONTAINER_NAME_PREFIX = 'gie_'
log = logging.getLogger(__name__)
@@ -50,7 +54,8 @@ class InteractiveEnvironmentRequest(object):
self.load_container_interface()
self.attr.docker_hostname = self.attr.viz_config.get("docker", "docker_hostname")
self.attr.docker_connect_port = int(self.attr.viz_config.get("docker", "docker_connect_port")) or None
raw_docker_connect_port = self.attr.viz_config.get("docker", "docker_connect_port")
self.attr.docker_connect_port = int(raw_docker_connect_port) if raw_docker_connect_port else None
# Generate per-request passwords the IE plugin can use to configure
# the destination container.
@@ -438,6 +443,10 @@ class InteractiveEnvironmentRequest(object):
raise Exception("Attempting to launch disallowed image! %s not in list of allowed images [%s]"
% (image, ', '.join(self.allowed_images)))
# Do not allow a None volumes
if not volumes:
volumes = []
if additional_ids is not None:
volumes += self._idsToVolumes(additional_ids)
@@ -485,7 +494,10 @@ class InteractiveEnvironmentRequest(object):
inspect_data = inspect_data[0]
if 'Node' in inspect_data:
return inspect_data['Node']['IP']
elif self.attr.docker_hostname == "localhost":
elif self.attr.docker_hostname == "localhost" and not IS_OS_X:
# If this is on Docker of Mac OS X that Gateway will be an
# IP address only available in the Docker host VM - so we
# stick with localhost.
return inspect_data['NetworkSettings']['Gateway']
else:
return self.attr.docker_hostname
@@ -69,9 +69,13 @@ class RemoteUser( object ):
assert self.remote_user_header not in environ
environ[ self.remote_user_header ] = self.single_user
# Apache sets REMOTE_USER to the string '(null)' when using the
# Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
if environ.get(self.remote_user_header, '').startswith('(null)'):
# Throw away garbage headers.
# Apache sets REMOTE_USER to the string '(null)' when using the
# Rewrite* method for passing REMOTE_USER and a user is not authenticated.
# Any other possible values need to go here as well.
log.debug("Discarding invalid remote user header %s:%s.", self.remote_user_header, environ.get(self.remote_user_header, None))
environ.pop(self.remote_user_header)
if self.remote_user_header in environ:
# process remote user with configuration options.
if self.normalize_remote_user_email:
@@ -126,10 +130,7 @@ class RemoteUser( object ):
"""
return self.error( start_response, title, message )
# Apache sets REMOTE_USER to the string '(null)' when using the
# Rewrite* method for passing REMOTE_USER and a user is
# un-authenticated. Any other possible values need to go here as well.
if not environ.get(self.remote_user_header, '(null)').startswith('(null)'):
if environ.get(self.remote_user_header, None):
if not environ[ self.remote_user_header ].count( '@' ):
if self.maildomain is not None:
environ[ self.remote_user_header ] += '@' + self.maildomain
+13 -9
View File
@@ -385,7 +385,13 @@ class GalaxyWebTransaction( base.DefaultWebTransaction,
elif secure_id:
# API authentication via active session
# Associate user using existing session
self._ensure_valid_session( session_cookie )
# This will throw an exception under remote auth with anon users.
try:
self._ensure_valid_session( session_cookie )
except Exception:
log.exception("Exception during Session-based API authentication, this was most likely an attempt to use an anonymous cookie under remote authentication (so, no user), which we don't support.")
self.user = None
self.galaxy_session = None
else:
# Anonymous API interaction -- anything but @expose_api_anonymous will fail past here.
self.user = None
@@ -435,17 +441,13 @@ class GalaxyWebTransaction( base.DefaultWebTransaction,
# cases won't have a cookie set above, so we need to to check some
# things now.
if self.app.config.use_remote_user:
# If this is an api request, and they've passed a key, we let this go.
assert self.app.config.remote_user_header in self.environ, \
"use_remote_user is set but %s header was not provided" % self.app.config.remote_user_header
remote_user_email = self.environ[ self.app.config.remote_user_header ]
remote_user_email = self.environ.get( self.app.config.remote_user_header, None)
if galaxy_session:
# An existing session, make sure correct association exists
if galaxy_session.user is None:
if remote_user_email and galaxy_session.user is None:
# No user, associate
galaxy_session.user = self.get_or_create_remote_user( remote_user_email )
galaxy_session_requires_flush = True
elif (not remote_user_email.startswith('(null)') and # Apache does this, see remoteuser.py
elif (remote_user_email and
(galaxy_session.user.email != remote_user_email) and
((not self.app.config.allow_user_impersonation) or
(remote_user_email not in self.app.config.admin_users_list))):
@@ -456,9 +458,11 @@ class GalaxyWebTransaction( base.DefaultWebTransaction,
user_for_new_session = self.get_or_create_remote_user( remote_user_email )
log.warning( "User logged in as '%s' externally, but has a cookie as '%s' invalidating session",
remote_user_email, galaxy_session.user.email )
else:
elif remote_user_email:
# No session exists, get/create user for new session
user_for_new_session = self.get_or_create_remote_user( remote_user_email )
if ((galaxy_session and galaxy_session.user is None) and user_for_new_session is None):
raise Exception("Remote Authentication Failure - user is unknown and/or not supplied.")
else:
if galaxy_session is not None and galaxy_session.user and galaxy_session.user.external:
# Remote user support is not enabled, but there is an existing
+1 -1
View File
@@ -14,6 +14,6 @@
"eventemitter3": "0.1.6",
"http-proxy": "1.6.0",
"commander": "~2.2",
"sqlite3": "3.1.3"
"sqlite3": "3.1.8"
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+44
View File
@@ -895,6 +895,50 @@ steps:
content = self.dataset_populator.get_history_dataset_content( history_id )
self.assertEqual(content.strip(), "samp1\t10.0\nsamp2\t20.0\nsamp1\t20.0\nsamp2\t40.0")
def test_filter_failed_mapping( self ):
history_id = self.dataset_populator.new_history()
summary = self._run_jobs("""
class: GalaxyWorkflow
inputs:
- type: collection
label: input_c
steps:
- label: mixed_collection
tool_id: exit_code_from_file
state:
input:
$link: input_c
- label: filtered_collection
tool_id: "__FILTER_FAILED_DATASETS__"
state:
input:
$link: mixed_collection#out_file1
- tool_id: cat1
state:
input1:
$link: filtered_collection
test_data:
input_c:
type: list
elements:
- identifier: i1
content: "0"
- identifier: i2
content: "1"
""", history_id=history_id, wait=True, assert_ok=False)
jobs = summary.jobs
def filter_jobs_by_tool(tool_id):
return [j for j in summary.jobs if j["tool_id"] == tool_id]
assert len(filter_jobs_by_tool("upload1")) == 2, jobs
assert len(filter_jobs_by_tool("exit_code_from_file")) == 2, jobs
assert len(filter_jobs_by_tool("__FILTER_FAILED_DATASETS__")) == 1, jobs
# Follow proves one job was filtered out of the result of cat1
assert len(filter_jobs_by_tool("cat1")) == 1, jobs
def test_workflow_request( self ):
workflow = self.workflow_populator.load_workflow( name="test_for_queue" )
workflow_request, history_id = self._setup_workflow_run( workflow )
+2 -2
View File
@@ -698,11 +698,11 @@ define([ 'test-app', 'mvc/ui/ui-misc', 'mvc/ui/ui-select-content', 'mvc/ui/ui-dr
firstvalue : 'id0',
firstlabel : 'hid0: name0',
firstmultiple : true,
totalmultiple : 1,
totalmultiple : 2,
lastvalue : 'id2',
lastlabel : 'hid2: name2',
lastlength : 3,
lastmultiple : false });
lastmultiple : true });
select.model.set( 'multiple', false );
select.model.set( 'type', 'data_collection' );