blob: dd6dd970d1aa7b8fd32a6e749736885633e84524 [file] [log] [blame]
import logging
from airavata.model.application.io.ttypes import DataType
from airavata.model.group.ttypes import ResourcePermissionType
from django.conf import settings
from airavata_django_portal_sdk import remoteapi
from airavata_django_portal_sdk.user_storage import api as user_storage
logger = logging.getLogger(__name__)
def launch(request, experiment_id):
if remoteapi.is_remote_api_configured():
resp = remoteapi.call(request,
"/experiments/{experiment_id}/launch/",
path_params={"experiment_id": experiment_id},
base_url="/api",
method="post")
data = resp.json()
if not data["success"]:
logger.error(f"Failed to launch experiment {experiment_id}: {data['errorMessage']})")
raise Exception(data["errorMessage"])
return
else:
experiment = request.airavata_client.getExperiment(
request.authz_token, experiment_id)
_set_storage_id_and_data_dir(request, experiment)
_move_tmp_input_file_uploads_to_data_dir(request, experiment)
request.airavata_client.updateExperiment(
request.authz_token, experiment_id, experiment)
request.airavata_client.launchExperiment(
request.authz_token, experiment_id, settings.GATEWAY_ID)
def clone(request, experiment_id):
"""Clone experiment and return the experiment id of the clone."""
if remoteapi.is_remote_api_configured():
resp = remoteapi.call(request,
"/experiments/{experiment_id}/clone/",
path_params={"experiment_id": experiment_id},
base_url="/api",
method="post")
data = resp.json()
return data['experimentId']
else:
# figure what project to clone into
experiment = request.airavata_client.getExperiment(
request.authz_token, experiment_id)
project_id = _get_writeable_project(request, experiment)
# clone experiment
cloned_experiment_id = request.airavata_client.cloneExperiment(
request.authz_token, experiment_id,
"Clone of {}".format(experiment.experimentName), project_id)
cloned_experiment = request.airavata_client.getExperiment(
request.authz_token, cloned_experiment_id)
# Create a copy of the experiment input files
_copy_cloned_experiment_input_uris(request, cloned_experiment)
# Null out experimentDataDir so a new one will get created at launch
# time
cloned_experiment.userConfigurationData.experimentDataDir = None
request.airavata_client.updateExperiment(
request.authz_token, cloned_experiment.experimentId, cloned_experiment
)
return cloned_experiment_id
def _set_storage_id_and_data_dir(request, experiment):
# Storage ID
experiment.userConfigurationData.storageId = user_storage.get_default_storage_resource_id(request)
# Create experiment dir and set it on model
if not experiment.userConfigurationData.experimentDataDir:
project = request.airavata_client.getProject(
request.authz_token, experiment.projectId)
_, exp_dir = user_storage.create_user_dir(
request,
dir_names=(project.name, experiment.experimentName),
create_unique=True)
experiment.userConfigurationData.experimentDataDir = exp_dir
else:
# create_user_dir will also validate that absolute paths are
# inside the user's storage directory
_, exp_dir = user_storage.create_user_dir(
request,
path=experiment.userConfigurationData.experimentDataDir)
experiment.userConfigurationData.experimentDataDir = exp_dir
def _move_tmp_input_file_uploads_to_data_dir(request, experiment):
exp_data_dir = experiment.userConfigurationData.experimentDataDir
for experiment_input in experiment.experimentInputs:
if experiment_input.type == DataType.URI:
if experiment_input.value:
experiment_input.value = \
_move_if_tmp_input_file_upload(
request, experiment_input.value, exp_data_dir)
elif experiment_input.type == DataType.URI_COLLECTION:
data_product_uris = experiment_input.value.split(
",") if experiment_input.value else []
moved_data_product_uris = []
for data_product_uri in data_product_uris:
moved_data_product_uris.append(
_move_if_tmp_input_file_upload(request, data_product_uri,
exp_data_dir))
experiment_input.value = ",".join(moved_data_product_uris)
def _move_if_tmp_input_file_upload(
request, data_product_uri, experiment_data_dir):
"""
Conditionally moves tmp input file to data dir and returns new dp URI.
"""
data_product = request.airavata_client.getDataProduct(
request.authz_token, data_product_uri)
if user_storage.is_input_file(
request, data_product):
moved_data_product = \
user_storage.move(request, data_product=data_product, path=experiment_data_dir)
return moved_data_product.productUri
else:
return data_product_uri
def _get_writeable_project(request, experiment):
# figure what project to clone into:
# 1) project of this experiment if writeable
# 2) else, first writeable project
project_id = experiment.projectId
if _can_write(request, project_id):
return project_id
user_projects = request.airavata_client.getUserProjects(
request.authz_token, settings.GATEWAY_ID, request.user.username, -1, 0)
for user_project in user_projects:
if _can_write(request, user_project.projectID):
return user_project.projectID
raise Exception(
"Could not find writeable project for user {} in "
"gateway {}".format(request.user.username, settings.GATEWAY_ID))
def _can_write(request, entity_id):
return request.airavata_client.userHasAccess(
request.authz_token, entity_id, ResourcePermissionType.WRITE)
def _copy_cloned_experiment_input_uris(request, cloned_experiment):
# update the experimentInputs of type URI, copying input files into the
# tmp input files directory of the data store
for experiment_input in cloned_experiment.experimentInputs:
# skip inputs without values
if not experiment_input.value:
continue
if experiment_input.type == DataType.URI:
cloned_data_product = _copy_experiment_input_uri(request,
experiment_input.value)
if cloned_data_product is None:
logger.warning("Setting cloned input {} to null".format(
experiment_input.name))
experiment_input.value = None
else:
experiment_input.value = cloned_data_product.productUri
elif experiment_input.type == DataType.URI_COLLECTION:
data_product_uris = experiment_input.value.split(
",") if experiment_input.value else []
cloned_data_product_uris = []
for data_product_uri in data_product_uris:
cloned_data_product = _copy_experiment_input_uri(request,
data_product_uri)
if cloned_data_product is None:
logger.warning(
"Omitting a cloned input value for {}".format(
experiment_input.name))
else:
cloned_data_product_uris.append(
cloned_data_product.productUri)
experiment_input.value = ",".join(cloned_data_product_uris)
def _copy_experiment_input_uri(request, data_product_uri):
if user_storage.exists(request, data_product_uri=data_product_uri):
return user_storage._copy_input_file(
request, data_product_uri=data_product_uri)
else:
logger.warning("Could not find file for source data "
"product {}".format(data_product_uri))
return None