@orcabus/platform-cdk-constructs 0.0.5 → 0.0.7-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +859 -10
- package/api-gateway/api-gateway.js +22 -4
- package/deployment-stack-pipeline/pipeline.js +8 -5
- package/dynamodb/config.d.ts +3 -0
- package/dynamodb/config.js +7 -0
- package/dynamodb/index.d.ts +27 -0
- package/dynamodb/index.js +106 -0
- package/ecs/config.d.ts +4 -0
- package/ecs/config.js +8 -0
- package/ecs/index.d.ts +46 -0
- package/ecs/index.js +103 -0
- package/index.d.ts +5 -2
- package/index.js +47 -5
- package/index.ts +16 -2
- package/lambda/build_python/Dockerfile +60 -0
- package/lambda/config.d.ts +11 -0
- package/lambda/config.js +19 -0
- package/lambda/index.d.ts +59 -0
- package/lambda/index.js +242 -0
- package/lambda/layers/mart_tools/poetry.lock +303 -0
- package/lambda/layers/mart_tools/pyproject.toml +27 -0
- package/lambda/layers/mart_tools/src/mart_tools/__init__.py +0 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/__init__.py +8 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/aws_helpers.py +79 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/dataframe_helpers.py +29 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/globals.py +5 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/models.py +71 -0
- package/lambda/layers/orcabus_api_tools/poetry.lock +273 -0
- package/lambda/layers/orcabus_api_tools/pyproject.toml +27 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/__init__.py +0 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/__init__.py +172 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/create_helpers.py +47 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/globals.py +13 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/job_helpers.py +53 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/models.py +253 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/query_helpers.py +248 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/update_helpers.py +221 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/workflow_helpers.py +25 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/__init__.py +92 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/create_helpers.py +27 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/globals.py +21 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/models.py +51 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/query_helpers.py +52 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/update_helpers.py +45 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/__init__.py +98 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/errors.py +45 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/file_helpers.py +341 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/globals.py +70 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/models.py +59 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/__init__.py +8 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/aws_helpers.py +79 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/dataframe_helpers.py +29 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/globals.py +5 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/models.py +71 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/__init__.py +250 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/contact_helpers.py +109 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/errors.py +104 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/globals.py +16 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/individual_helpers.py +139 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/library_helpers.py +196 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/lims_helpers.py +36 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/models.py +112 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/project_helpers.py +129 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/sample_helpers.py +132 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/subject_helpers.py +151 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/__init__.py +15 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/globals.py +2 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/models.py +44 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/sequence_helpers.py +62 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/__init__.py +0 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/aws_helpers.py +123 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/miscell.py +17 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/requests_helpers.py +163 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/__init__.py +0 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/errors.py +37 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/metadata_helpers.py +28 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/models.py +85 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/payload_helpers.py +64 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/workflow_run_helpers.py +80 -0
- package/package.json +14 -11
- package/typedoc.json +3 -0
- package/utils/index.d.ts +3 -0
- package/utils/index.js +50 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Helper functions for a subject
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
# Standard imports
|
|
9
|
+
from typing import List
|
|
10
|
+
from requests import HTTPError
|
|
11
|
+
|
|
12
|
+
# Local imports
|
|
13
|
+
from . import get_metadata_request_response_results, get_item_objs_from_item_id_list
|
|
14
|
+
from .errors import SubjectNotFoundError
|
|
15
|
+
from .globals import SUBJECT_ENDPOINT, ORCABUS_ULID_REGEX_MATCH
|
|
16
|
+
from .models import Subject, Sample, LibraryDetail
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_subject_from_subject_id(subject_id: str) -> Subject:
|
|
20
|
+
"""
|
|
21
|
+
Get subject from the subject id
|
|
22
|
+
:param subject_id:
|
|
23
|
+
:return:
|
|
24
|
+
"""
|
|
25
|
+
# We have an internal id, convert to int
|
|
26
|
+
params = {
|
|
27
|
+
"subject_id": subject_id
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Get subject
|
|
31
|
+
try:
|
|
32
|
+
query_results = get_metadata_request_response_results(SUBJECT_ENDPOINT, params)
|
|
33
|
+
assert len(query_results) == 1
|
|
34
|
+
return query_results[0]
|
|
35
|
+
except (HTTPError, AssertionError):
|
|
36
|
+
raise SubjectNotFoundError(
|
|
37
|
+
subject_id=subject_id
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_subjects_list_from_subject_id_list(subject_id_list: List[str], accept_missing: bool = False) -> List[Sample]:
|
|
42
|
+
"""
|
|
43
|
+
Get sample from the sample id
|
|
44
|
+
:param sample_id:
|
|
45
|
+
:return:
|
|
46
|
+
"""
|
|
47
|
+
# We have an internal id, convert to int
|
|
48
|
+
return list(map(
|
|
49
|
+
lambda sample_iter_: Sample(**sample_iter_),
|
|
50
|
+
get_item_objs_from_item_id_list(
|
|
51
|
+
item_id_list=subject_id_list,
|
|
52
|
+
item_identifier="subjectId",
|
|
53
|
+
endpoint=SUBJECT_ENDPOINT,
|
|
54
|
+
accept_missing=accept_missing
|
|
55
|
+
)
|
|
56
|
+
))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def coerce_subject_id_or_orcabus_id_to_subject_orcabus_id(id_: str) -> str:
|
|
60
|
+
if ORCABUS_ULID_REGEX_MATCH.match(id_):
|
|
61
|
+
return id_
|
|
62
|
+
else :
|
|
63
|
+
return get_subject_orcabus_id_from_subject_id(id_)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_subject_orcabus_id_from_subject_id(subject_id: str) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Get the subject orcabus id from the subject id
|
|
69
|
+
:param subject_id:
|
|
70
|
+
:return:
|
|
71
|
+
"""
|
|
72
|
+
return get_subject_from_subject_id(subject_id)['orcabusId']
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_subjects_list_from_subject_orcabus_id_list(subject_orcabus_id_list: List[str], accept_missing: bool = False) -> List[Sample]:
|
|
76
|
+
"""
|
|
77
|
+
Get sample from the sample id
|
|
78
|
+
:param sample_id:
|
|
79
|
+
:return:
|
|
80
|
+
"""
|
|
81
|
+
# We have an internal id, convert to int
|
|
82
|
+
return list(map(
|
|
83
|
+
lambda sample_iter_: Sample(**sample_iter_),
|
|
84
|
+
get_item_objs_from_item_id_list(
|
|
85
|
+
item_id_list=subject_orcabus_id_list,
|
|
86
|
+
item_identifier="subjectId",
|
|
87
|
+
endpoint=SUBJECT_ENDPOINT,
|
|
88
|
+
accept_missing=accept_missing
|
|
89
|
+
)
|
|
90
|
+
))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_subject_from_subject_orcabus_id(subject_orcabus_id: str) -> Subject:
|
|
94
|
+
"""
|
|
95
|
+
Get subject from the subject id
|
|
96
|
+
:param subject_orcabus_id:
|
|
97
|
+
:return:
|
|
98
|
+
"""
|
|
99
|
+
# Get subject id
|
|
100
|
+
# We have an internal id, convert to int
|
|
101
|
+
params = {
|
|
102
|
+
"orcabus_id": subject_orcabus_id
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Get subject
|
|
106
|
+
try:
|
|
107
|
+
query_results = get_metadata_request_response_results(SUBJECT_ENDPOINT, params)
|
|
108
|
+
assert len(query_results) == 1
|
|
109
|
+
return query_results[0]
|
|
110
|
+
except (HTTPError, AssertionError):
|
|
111
|
+
raise SubjectNotFoundError(
|
|
112
|
+
subject_orcabus_id=subject_orcabus_id
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def list_samples_in_subject(subject_orcabus_id: str) -> List[Sample]:
|
|
117
|
+
"""
|
|
118
|
+
Given a subject id, list the samples in the subject
|
|
119
|
+
:param subject_orcabus_id:
|
|
120
|
+
:return:
|
|
121
|
+
"""
|
|
122
|
+
from .sample_helpers import get_sample_from_sample_orcabus_id
|
|
123
|
+
|
|
124
|
+
# Get the subject
|
|
125
|
+
return list(map(
|
|
126
|
+
# For each subject, get libraries in subject
|
|
127
|
+
lambda library_iter_: get_sample_from_sample_orcabus_id(library_iter_['sample']['orcabusId']),
|
|
128
|
+
# Get list of subject orcabus ids
|
|
129
|
+
list_libraries_in_subject(subject_orcabus_id)
|
|
130
|
+
))
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def list_libraries_in_subject(subject_orcabus_id: str) -> List[LibraryDetail]:
|
|
134
|
+
"""
|
|
135
|
+
Given a subject id, return the list of library objects in the subject
|
|
136
|
+
:param subject_orcabus_id:
|
|
137
|
+
:return:
|
|
138
|
+
"""
|
|
139
|
+
# Get ID For Subject
|
|
140
|
+
subject = get_subject_from_subject_orcabus_id(subject_orcabus_id)
|
|
141
|
+
|
|
142
|
+
# Get the subject
|
|
143
|
+
return subject.get("librarySet", [])
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def get_all_subjects() -> List[Subject]:
|
|
147
|
+
"""
|
|
148
|
+
Get all subjects
|
|
149
|
+
:return:
|
|
150
|
+
"""
|
|
151
|
+
return get_metadata_request_response_results(SUBJECT_ENDPOINT)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from sequence_helpers import (
|
|
4
|
+
get_sequence_object_from_instrument_run_id,
|
|
5
|
+
get_sample_sheet_from_orcabus_id,
|
|
6
|
+
get_library_ids_in_sequence,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"get_sequence_object_from_instrument_run_id",
|
|
11
|
+
"get_sample_sheet_from_orcabus_id",
|
|
12
|
+
"get_library_ids_in_sequence",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
from typing import TypedDict, Literal, NotRequired, Optional, Dict
|
|
4
|
+
|
|
5
|
+
statusLiteral = Literal['STARTED', 'FAILED', 'SUCCEEDED', 'ABORTED', 'RESOLVED']
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SequenceDetail(TypedDict):
|
|
9
|
+
orcabusId: str
|
|
10
|
+
instrumentRunId: str
|
|
11
|
+
experimentName: str
|
|
12
|
+
startTime: str
|
|
13
|
+
endTime: str
|
|
14
|
+
status: statusLiteral
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Sequence(TypedDict):
|
|
18
|
+
orcabusId: str
|
|
19
|
+
libraries: str
|
|
20
|
+
sequenceRunId: str
|
|
21
|
+
status: statusLiteral
|
|
22
|
+
startTime: str
|
|
23
|
+
sampleSheetName: str
|
|
24
|
+
v1pre3Id: str
|
|
25
|
+
icaProjectId: str
|
|
26
|
+
apiUrl: str
|
|
27
|
+
endTime: str
|
|
28
|
+
runVolumeName: str
|
|
29
|
+
runFolderPath: str
|
|
30
|
+
runDataUri: str
|
|
31
|
+
instrumentRunId: str
|
|
32
|
+
reagentBarcode: str
|
|
33
|
+
flowcellBarcode: str
|
|
34
|
+
sequenceRunName: str
|
|
35
|
+
experimentName: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SampleSheet(TypedDict):
|
|
39
|
+
orcabusId: str
|
|
40
|
+
sampleSheetName: str
|
|
41
|
+
associationStatus: str
|
|
42
|
+
associationTimestamp: str
|
|
43
|
+
sampleSheetContent: Optional[Dict]
|
|
44
|
+
sequence: str
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from .globals import SEQUENCE_SUBDOMAIN_NAME
|
|
3
|
+
from .models import Sequence, SequenceDetail, SampleSheet
|
|
4
|
+
from ..utils.requests_helpers import get_request_response_results, get_request, get_url
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_sequence_url(endpoint: str) -> str:
|
|
8
|
+
"""
|
|
9
|
+
Get the URL for the Metadata endpoint
|
|
10
|
+
:param endpoint:
|
|
11
|
+
:return:
|
|
12
|
+
"""
|
|
13
|
+
return get_url(
|
|
14
|
+
endpoint,
|
|
15
|
+
SEQUENCE_SUBDOMAIN_NAME
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def get_sequence_object_from_instrument_run_id(instrument_run_id: str) -> SequenceDetail:
|
|
19
|
+
"""
|
|
20
|
+
Get the sequence object from the instrument run id.
|
|
21
|
+
:param instrument_run_id:
|
|
22
|
+
:return:
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
return Sequence(
|
|
26
|
+
**dict(
|
|
27
|
+
get_request_response_results(
|
|
28
|
+
get_sequence_url(endpoint="api/v1/sequence"),
|
|
29
|
+
params={
|
|
30
|
+
"instrumentRunId": instrument_run_id,
|
|
31
|
+
}
|
|
32
|
+
)[0]
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_sample_sheet_from_orcabus_id(sequence_orcabus_id: str) -> SampleSheet:
|
|
38
|
+
"""
|
|
39
|
+
Get the sample sheet from the orcabus id.
|
|
40
|
+
:param sequence_orcabus_id:
|
|
41
|
+
:return:
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
return SampleSheet(
|
|
45
|
+
**dict(
|
|
46
|
+
get_request(
|
|
47
|
+
get_sequence_url(endpoint=f"api/v1/sequence/{sequence_orcabus_id}/sample_sheet")
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_library_ids_in_sequence(sequence_orcabus_id: str) -> list[str]:
|
|
54
|
+
"""
|
|
55
|
+
Get the library ids in the sequence run.
|
|
56
|
+
:param sequence_orcabus_id:
|
|
57
|
+
:return:
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
return get_request(
|
|
61
|
+
get_sequence_url(endpoint=f"api/v1/sequence/{sequence_orcabus_id}")
|
|
62
|
+
)['libraries']
|
|
File without changes
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# Standard imports
|
|
4
|
+
import typing
|
|
5
|
+
from typing import Optional
|
|
6
|
+
import boto3
|
|
7
|
+
import json
|
|
8
|
+
from os import environ
|
|
9
|
+
import urllib3
|
|
10
|
+
from urllib.parse import urlunparse
|
|
11
|
+
|
|
12
|
+
# Type hinting
|
|
13
|
+
if typing.TYPE_CHECKING:
|
|
14
|
+
from mypy_boto3_secretsmanager import SecretsManagerClient
|
|
15
|
+
from mypy_boto3_ssm import SSMClient
|
|
16
|
+
|
|
17
|
+
# Set globals
|
|
18
|
+
ORCABUS_TOKEN_STR: Optional[str] = None
|
|
19
|
+
HOSTNAME_STR: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
http = urllib3.PoolManager()
|
|
22
|
+
|
|
23
|
+
LOCAL_HTTP_CACHE_PORT = 2773
|
|
24
|
+
PARAMETER_URL = '/systemsmanager/parameters/get/'
|
|
25
|
+
SECRETS_URL = '/secretsmanager/get/'
|
|
26
|
+
|
|
27
|
+
def retrieve_extension_value(url, query):
|
|
28
|
+
url = str(urlunparse((
|
|
29
|
+
'http', f'localhost:{LOCAL_HTTP_CACHE_PORT}',
|
|
30
|
+
url, None,
|
|
31
|
+
"&".join(list(map(
|
|
32
|
+
lambda kv: f"{kv[0]}={kv[1]}",
|
|
33
|
+
query.items()
|
|
34
|
+
))), None
|
|
35
|
+
)))
|
|
36
|
+
headers = {
|
|
37
|
+
"X-Aws-Parameters-Secrets-Token": environ.get('AWS_SESSION_TOKEN')
|
|
38
|
+
}
|
|
39
|
+
response = http.request("GET", url, headers=headers)
|
|
40
|
+
response = json.loads(response.data)
|
|
41
|
+
return response
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_ssm_value_from_cache(parameter_name: str) -> Optional[str]:
|
|
45
|
+
try:
|
|
46
|
+
return retrieve_extension_value(
|
|
47
|
+
PARAMETER_URL,
|
|
48
|
+
{
|
|
49
|
+
"name": parameter_name,
|
|
50
|
+
}
|
|
51
|
+
)['Parameter']['Value']
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print("Got an exception while trying to get ssm value from cache")
|
|
54
|
+
print(e)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_secret_value_from_cache(secret_id: str) -> Optional[str]:
|
|
59
|
+
try:
|
|
60
|
+
return retrieve_extension_value(
|
|
61
|
+
SECRETS_URL,
|
|
62
|
+
{
|
|
63
|
+
"secretId": secret_id,
|
|
64
|
+
}
|
|
65
|
+
)['SecretString']
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print("Got an exception while trying to get secret value from cache")
|
|
68
|
+
print(e)
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
def get_secretsmanager_client() -> 'SecretsManagerClient':
|
|
72
|
+
return boto3.client('secretsmanager')
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_ssm_client() -> 'SSMClient':
|
|
76
|
+
return boto3.client('ssm')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_secret_value(secret_id) -> str:
|
|
80
|
+
"""
|
|
81
|
+
Collect the secret value
|
|
82
|
+
:param secret_id:
|
|
83
|
+
:return:
|
|
84
|
+
"""
|
|
85
|
+
secret_value_cached = get_secret_value_from_cache(secret_id)
|
|
86
|
+
if secret_value_cached is not None:
|
|
87
|
+
return secret_value_cached
|
|
88
|
+
|
|
89
|
+
# Get the boto3 response
|
|
90
|
+
get_secret_value_response = get_secretsmanager_client().get_secret_value(SecretId=secret_id)
|
|
91
|
+
|
|
92
|
+
return get_secret_value_response['SecretString']
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_ssm_value(parameter_name) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Collect the parameter from SSM
|
|
98
|
+
:param parameter_name:
|
|
99
|
+
:return:
|
|
100
|
+
"""
|
|
101
|
+
ssm_parameter_cached = get_ssm_value_from_cache(parameter_name)
|
|
102
|
+
if ssm_parameter_cached is not None:
|
|
103
|
+
return ssm_parameter_cached
|
|
104
|
+
|
|
105
|
+
# Get the boto3 response
|
|
106
|
+
get_ssm_parameter_response = get_ssm_client().get_parameter(Name=parameter_name)
|
|
107
|
+
|
|
108
|
+
return get_ssm_parameter_response['Parameter']['Value']
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_orcabus_token() -> str:
|
|
112
|
+
"""
|
|
113
|
+
From the AWS Secrets Manager, retrieve the OrcaBus token.
|
|
114
|
+
:return:
|
|
115
|
+
"""
|
|
116
|
+
return (
|
|
117
|
+
json.loads(
|
|
118
|
+
get_secret_value(environ.get("ORCABUS_TOKEN_SECRET_ID"))
|
|
119
|
+
)['id_token']
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def get_hostname() -> str:
|
|
123
|
+
return get_ssm_value(environ.get("HOSTNAME_SSM_PARAMETER"))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from urllib.parse import urlparse
|
|
2
|
+
|
|
3
|
+
def get_bucket_key_pair_from_uri(s3_uri: str) -> (str, str):
|
|
4
|
+
"""
|
|
5
|
+
Get the bucket and key from an s3 uri
|
|
6
|
+
:param s3_uri:
|
|
7
|
+
:return:
|
|
8
|
+
"""
|
|
9
|
+
url_obj = urlparse(s3_uri)
|
|
10
|
+
|
|
11
|
+
s3_bucket = url_obj.netloc
|
|
12
|
+
s3_key = url_obj.path.lstrip('/')
|
|
13
|
+
|
|
14
|
+
if s3_bucket is None or s3_key is None:
|
|
15
|
+
raise ValueError(f"Invalid S3 URI: {s3_uri}")
|
|
16
|
+
|
|
17
|
+
return s3_bucket, s3_key
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from typing import Dict, Optional, List
|
|
3
|
+
from urllib.parse import urlunparse
|
|
4
|
+
|
|
5
|
+
# Standard imports
|
|
6
|
+
import requests
|
|
7
|
+
import logging
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
|
|
10
|
+
from requests import HTTPError
|
|
11
|
+
|
|
12
|
+
# Locals
|
|
13
|
+
from .aws_helpers import (
|
|
14
|
+
get_orcabus_token, get_hostname
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Globals
|
|
18
|
+
DEFAULT_REQUEST_PARAMS = {
|
|
19
|
+
"rowsPerPage": 1000
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Set logging
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
logger.setLevel(logging.INFO)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_url(
|
|
28
|
+
endpoint: str,
|
|
29
|
+
subdomain: str
|
|
30
|
+
) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Get the URL for the Metadata endpoint
|
|
33
|
+
:param endpoint:
|
|
34
|
+
:return:
|
|
35
|
+
"""
|
|
36
|
+
# Get the hostname
|
|
37
|
+
hostname = get_hostname()
|
|
38
|
+
|
|
39
|
+
return str(urlunparse((
|
|
40
|
+
"https",
|
|
41
|
+
".".join([subdomain, hostname]),
|
|
42
|
+
endpoint,
|
|
43
|
+
None, None, None
|
|
44
|
+
)))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def get_request_response_results(url: str, params: Optional[Dict] = None) -> List[Dict]:
|
|
48
|
+
"""
|
|
49
|
+
Run get response against the Metadata endpoint
|
|
50
|
+
:param url:
|
|
51
|
+
:param params:
|
|
52
|
+
:return:
|
|
53
|
+
"""
|
|
54
|
+
# Get authorization header
|
|
55
|
+
headers = {
|
|
56
|
+
"Authorization": f"Bearer {get_orcabus_token()}"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
req_params = deepcopy(DEFAULT_REQUEST_PARAMS)
|
|
60
|
+
|
|
61
|
+
req_params.update(
|
|
62
|
+
params if params is not None else {}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Make the request
|
|
67
|
+
response = requests.get(
|
|
68
|
+
url,
|
|
69
|
+
headers=headers,
|
|
70
|
+
params=req_params
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
response.raise_for_status()
|
|
74
|
+
|
|
75
|
+
response_json = response.json()
|
|
76
|
+
|
|
77
|
+
if 'links' not in response_json.keys():
|
|
78
|
+
return [response_json]
|
|
79
|
+
|
|
80
|
+
if 'next' in response_json['links'].keys() and response_json['links']['next'] is not None:
|
|
81
|
+
return response_json['results'] + get_request_response_results(response_json['links']['next'])
|
|
82
|
+
return response_json['results']
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_request(url: str, params: Optional[Dict] = None) -> Dict:
|
|
86
|
+
# Get authorization header
|
|
87
|
+
headers = {
|
|
88
|
+
"Authorization": f"Bearer {get_orcabus_token()}"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Make the request
|
|
92
|
+
response = requests.get(
|
|
93
|
+
url,
|
|
94
|
+
headers=headers,
|
|
95
|
+
params=params if params is not None else {}
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
response.raise_for_status()
|
|
100
|
+
except HTTPError as e:
|
|
101
|
+
raise HTTPError(f"Error {e} - {response.text}") from e
|
|
102
|
+
|
|
103
|
+
return response.json()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def patch_request(url: str, params: Optional[Dict] = None) -> Dict:
|
|
107
|
+
# Get authorization header
|
|
108
|
+
headers = {
|
|
109
|
+
"Authorization": f"Bearer {get_orcabus_token()}"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
req_params = deepcopy(DEFAULT_REQUEST_PARAMS)
|
|
113
|
+
|
|
114
|
+
req_params.update(
|
|
115
|
+
params if params is not None else {}
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Make the request
|
|
119
|
+
response = requests.patch(
|
|
120
|
+
url,
|
|
121
|
+
headers=headers,
|
|
122
|
+
json=req_params
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
response.raise_for_status()
|
|
127
|
+
except HTTPError as e:
|
|
128
|
+
raise HTTPError(f"Error {e} - {response.text}") from e
|
|
129
|
+
|
|
130
|
+
return response.json()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def post_request(url: str, params: Optional[Dict] = None) -> Dict:
|
|
134
|
+
"""
|
|
135
|
+
Run post request against the fastq endpoint
|
|
136
|
+
:param url:
|
|
137
|
+
:param params:
|
|
138
|
+
:return:
|
|
139
|
+
"""
|
|
140
|
+
# Get authorization header
|
|
141
|
+
headers = {
|
|
142
|
+
"Authorization": f"Bearer {get_orcabus_token()}"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
req_params = deepcopy(DEFAULT_REQUEST_PARAMS)
|
|
146
|
+
|
|
147
|
+
req_params.update(
|
|
148
|
+
params if params is not None else {}
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Make the request
|
|
152
|
+
response = requests.post(
|
|
153
|
+
url,
|
|
154
|
+
headers=headers,
|
|
155
|
+
json=req_params
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
response.raise_for_status()
|
|
160
|
+
except HTTPError as e:
|
|
161
|
+
raise HTTPError(f"Error {e} - {response.text}") from e
|
|
162
|
+
|
|
163
|
+
return response.json()
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class WorkflowRunNotFoundError(Exception):
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
workflow_run_id: Optional[str] = None,
|
|
8
|
+
portal_run_id: Optional[str] = None,
|
|
9
|
+
):
|
|
10
|
+
self.workflow_run_id = workflow_run_id
|
|
11
|
+
self.portal_run_id = portal_run_id
|
|
12
|
+
if workflow_run_id is not None:
|
|
13
|
+
self.message = f"Could not find workflow with orcabus run id '{workflow_run_id}'"
|
|
14
|
+
elif portal_run_id is not None:
|
|
15
|
+
self.message = f"Could not find workflow run portal run id '{portal_run_id}'"
|
|
16
|
+
else:
|
|
17
|
+
self.message = "Could not find workflow"
|
|
18
|
+
super().__init__(self.message)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class WorkflowRunStateNotFoundError(Exception):
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
workflow_run_id: Optional[str] = None,
|
|
25
|
+
portal_run_id: Optional[str] = None,
|
|
26
|
+
status: Optional[str] = None,
|
|
27
|
+
):
|
|
28
|
+
self.workflow_run_id = workflow_run_id
|
|
29
|
+
self.portal_run_id = portal_run_id
|
|
30
|
+
self.status = status
|
|
31
|
+
if workflow_run_id is not None:
|
|
32
|
+
self.message = f"Could not find workflow with orcabus run id '{workflow_run_id}', status '{status}'"
|
|
33
|
+
elif portal_run_id is not None:
|
|
34
|
+
self.message = f"Could not find workflow run portal run id '{portal_run_id}', status '{status}'"
|
|
35
|
+
else:
|
|
36
|
+
self.message = "Could not find workflow"
|
|
37
|
+
super().__init__(self.message)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Get workflows from library id
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Standard imports
|
|
8
|
+
from typing import List
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Local imports
|
|
12
|
+
from .requests_helpers import get_request_response_results
|
|
13
|
+
from .globals import WORKFLOW_RUN_ENDPOINT
|
|
14
|
+
from .models import WorkflowRunDetail
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_workflows_from_library_id(library_id: str) -> List[WorkflowRunDetail]:
|
|
18
|
+
"""
|
|
19
|
+
Use the query libraries__libraryId to get workflows from a library id
|
|
20
|
+
:param library_id:
|
|
21
|
+
:return:
|
|
22
|
+
"""
|
|
23
|
+
return get_request_response_results(
|
|
24
|
+
WORKFLOW_RUN_ENDPOINT,
|
|
25
|
+
params={
|
|
26
|
+
"libraries__libraryId": library_id
|
|
27
|
+
}
|
|
28
|
+
)
|