diff --git a/delivery/handlers/dds_handlers.py b/delivery/handlers/dds_handlers.py index 4197bd7..ed5e946 100644 --- a/delivery/handlers/dds_handlers.py +++ b/delivery/handlers/dds_handlers.py @@ -3,6 +3,8 @@ from delivery.handlers import * from delivery.handlers.utility_handlers import ArteriaDeliveryBaseHandler +import os +import tempfile import logging log = logging.getLogger(__name__) @@ -25,7 +27,8 @@ async def post(self, project_name): Create a new project in DDS. The project description as well as the email of its pi must be specified in the request body. Project owners, researchers, and whether the data is sensitive or not (default is yes), - can also be specified there. E.g.: + can also be specified there. "auth_token" can be either the path to + the authentication token or the token itself. E.g.: import requests @@ -37,16 +40,30 @@ async def post(self, project_name): "researchers": ["robin@doe.com", "kim@doe.com"], "owners": ["alex@doe.com"], "non-sensitive": False, - "token_path": "/foo/bar" + "auth_token": "1234" } response = requests.request("POST", url, json=payload) """ - required_members = ["token_path"] - project_metadata = self.body_as_object(required_members=required_members) + required_members = ["auth_token"] + project_metadata = self.body_as_object( + required_members=required_members) - dds_project_id = await self.dds_service.create_dds_project(project_name, project_metadata) + with tempfile.NamedTemporaryFile(mode='w', delete=True) as token_file: + if os.path.exists(project_metadata["auth_token"]): + token_path = project_metadata["auth_token"] + else: + token_file.write(project_metadata["auth_token"]) + token_file.flush() + + token_path = token_file.name + + dds_project_id = await self.dds_service.create_dds_project( + project_name, + project_metadata, + token_path, + ) self.set_status(ACCEPTED) self.write_json({'dds_project_id': dds_project_id}) diff --git a/delivery/handlers/delivery_handlers.py b/delivery/handlers/delivery_handlers.py index 7e254fc..606636b 100644 --- a/delivery/handlers/delivery_handlers.py +++ b/delivery/handlers/delivery_handlers.py @@ -1,6 +1,8 @@ +import os import json import logging +import tempfile from tornado.gen import coroutine @@ -24,16 +26,14 @@ def initialize(self, **kwargs): def post(self, staging_id): required_members = ["delivery_project_id"] if self.dds: - required_members += ["token_path"] + required_members += ["auth_token"] request_data = self.body_as_object(required_members=required_members) delivery_project_id = request_data["delivery_project_id"] - token_path = request_data.get("token_path") + auth_token = request_data.get("auth_token") md5sum_file = request_data.get("md5sums_file") extra_args = {} - if token_path: - extra_args['token_path'] = token_path # This should only be used for testing purposes /JD 20170202 skip_mover_request = request_data.get("skip_mover") @@ -44,12 +44,24 @@ def post(self, staging_id): log.debug("Will not skip running mover!") skip_mover = False - delivery_id = yield self.delivery_service.deliver_by_staging_id( - staging_id=staging_id, - delivery_project=delivery_project_id, - md5sum_file=md5sum_file, - skip_mover=skip_mover, - **extra_args) + with tempfile.NamedTemporaryFile(mode='w', delete=True) as token_file: + if auth_token: + if os.path.exists(auth_token): + token_path = auth_token + else: + token_file.write(auth_token) + token_file.flush() + + token_path = token_file.name + + extra_args['token_path'] = token_path + + delivery_id = yield self.delivery_service.deliver_by_staging_id( + staging_id=staging_id, + delivery_project=delivery_project_id, + md5sum_file=md5sum_file, + skip_mover=skip_mover, + **extra_args) status_end_point = "{0}://{1}{2}".format(self.request.protocol, self.request.host, diff --git a/delivery/services/dds_service.py b/delivery/services/dds_service.py index 67ee913..5d19708 100644 --- a/delivery/services/dds_service.py +++ b/delivery/services/dds_service.py @@ -41,18 +41,23 @@ def _parse_dds_project_id(dds_output): else: raise CannotParseDDSOutputException(f"Could not parse DDS project ID from: {dds_output}") - async def create_dds_project(self, project_name, project_metadata): + async def create_dds_project( + self, + project_name, + project_metadata, + token_path): """ Create a new project in dds :param project_name: Project name from Clarity :param project_metadata: dictionnary containing pi email, project description, owner and researcher emails as well as whether the data is sensitive or not. + :param token_path: path to DDS authentication token. :return: project id in dds """ cmd = [ 'dds', - '--token-path', project_metadata["token_path"], + '--token-path', token_path, '--log-file', self.dds_conf["log_path"], ] @@ -152,7 +157,13 @@ def _run_dds_put( session.commit() @gen.coroutine - def deliver_by_staging_id(self, staging_id, delivery_project, md5sum_file, token_path, skip_mover=False): + def deliver_by_staging_id( + self, + staging_id, + delivery_project, + md5sum_file, + token_path, + skip_mover=False): stage_order = self.staging_service.get_stage_order_by_id(staging_id) if not stage_order or not stage_order.status == StagingStatus.staging_successful: diff --git a/tests/integration_tests/test_integration_dds.py b/tests/integration_tests/test_integration_dds.py index ee3f46a..f33704a 100644 --- a/tests/integration_tests/test_integration_dds.py +++ b/tests/integration_tests/test_integration_dds.py @@ -60,7 +60,7 @@ def test_can_stage_and_delivery_runfolder(self): delivery_body = { 'delivery_project_id': 'fakedeliveryid2016', 'dds': True, - 'token_path': 'token_path', + 'auth_token': '1234', 'skip_mover': True, } delivery_resp = yield self.http_client.fetch(self.get_url(delivery_url), method='POST', body=json.dumps(delivery_body)) @@ -102,7 +102,7 @@ def test_can_stage_and_delivery_project_dir(self): 'delivery_project_id': 'fakedeliveryid2016', 'skip_mover': True, 'dds': True, - 'token_path': 'token_path', + 'auth_token': '1234', } delivery_resp = yield self.http_client.fetch(self.get_url(delivery_url), method='POST', body=json.dumps(delivery_body)) delivery_resp_as_json = json.loads(delivery_resp.body) @@ -214,7 +214,7 @@ def test_can_create_project(self): "researchers": ["robin@doe.com", "kim@doe.com"], "owners": ["alex@doe.com"], "non-sensitive": False, - "token_path": '/foo/bar/auth', + "auth_token": '1234', } response = yield self.http_client.fetch( @@ -234,7 +234,7 @@ def test_can_create_two_projects(self): "researchers": ["robin@doe.com", "kim@doe.com"], "owners": ["alex@doe.com"], "non-sensitive": False, - "token_path": '/foo/bar/auth', + "auth_token": '1234', } response = yield self.http_client.fetch( @@ -294,7 +294,7 @@ def test_can_deliver_and_respond(self): delivery_body = { 'delivery_project_id': 'fakedeliveryid2016', 'dds': True, - 'token_path': 'token_path', + 'auth_token': '1234', 'skip_mover': False, } delivery_response = self.http_client.fetch(self.get_url(delivery_url), method='POST', body=json.dumps(delivery_body)) diff --git a/tests/unit_tests/services/test_dds.py b/tests/unit_tests/services/test_dds.py index 0b725ed..44a952f 100644 --- a/tests/unit_tests/services/test_dds.py +++ b/tests/unit_tests/services/test_dds.py @@ -186,7 +186,7 @@ def test_parse_dds_project_id(self): self.assertEqual(DDSService._parse_dds_project_id(dds_output), "snpseq00003") @gen_test - def test_create_project(self): + def test_create_project_token_file(self): project_name = "AA-1221" project_metadata = { "description": "Dummy project", @@ -194,22 +194,29 @@ def test_create_project(self): "researchers": ["robin@doe.com", "kim@doe.com"], "owners": ["alex@doe.com"], "non-sensitive": False, - "token_path": "/foo/bar/auth", } + token_path = "/foo/bar/auth" + with patch( 'delivery.services.external_program_service' '.ExternalProgramService.run_and_wait', new_callable=AsyncMock) as mock_run,\ - patch('delivery.services.dds_service.DDSService._parse_dds_project_id') as mock_parse_dds_project_id: + patch( + 'delivery.services.dds_service' + '.DDSService._parse_dds_project_id' + ) as mock_parse_dds_project_id: mock_run.return_value.status_code = 0 mock_parse_dds_project_id.return_value = "snpseq00001" - yield self.dds_service.create_dds_project(project_name, project_metadata) + yield self.dds_service.create_dds_project( + project_name, + project_metadata, + token_path) mock_run.assert_called_once_with([ 'dds', - '--token-path', '/foo/bar/auth', + '--token-path', token_path, '--log-file', '/foo/bar/log', 'project', 'create', '--title', project_name, @@ -220,6 +227,6 @@ def test_create_project(self): '--researcher', project_metadata['researchers'][1], ]) self.mock_dds_project_repo.add_dds_project\ - .assert_called_once_with( - project_name=project_name, - dds_project_id=mock_parse_dds_project_id.return_value) + .assert_called_once_with( + project_name=project_name, + dds_project_id=mock_parse_dds_project_id.return_value)