firecloud-api-cds 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,1774 @@
1
+ """
2
+ This module provides python bindings for the Firecloud API.
3
+ For more details see https://software.broadinstitute.org/firecloud/
4
+
5
+ To see how the python bindings map to the RESTful endpoints view
6
+ the README at https://pypi.python.org/pypi/firecloud.
7
+ """
8
+
9
+ from __future__ import print_function
10
+ import json
11
+ import sys
12
+ import os
13
+ import io
14
+ import logging
15
+ import subprocess
16
+ try:
17
+ from collections.abc import Iterable
18
+ except ImportError:
19
+ from collections import Iterable
20
+
21
+ from six.moves.urllib.parse import urlencode, urljoin
22
+ from six import string_types
23
+
24
+ import inspect
25
+
26
+ import google.auth
27
+ from google.auth.exceptions import DefaultCredentialsError, RefreshError
28
+ from google.auth.transport.requests import AuthorizedSession, Request
29
+ from google.oauth2 import id_token
30
+
31
+ from .errors import FireCloudServerError
32
+ from .fccore import __fcconfig as fcconfig
33
+
34
+ FISS_USER_AGENT = "FISS/0.16.38"
35
+
36
+ # Set Global Authorized Session
37
+ __SESSION = None
38
+ __USER_ID = None
39
+
40
+ # Suppress warnings about project ID
41
+ logging.getLogger('google.auth').setLevel(logging.ERROR)
42
+
43
+ #################################################
44
+ # Utilities
45
+ #################################################
46
+ def _set_session():
47
+ """ Sets global __SESSION and __USER_ID if they haven't been set """
48
+ global __SESSION
49
+ global __USER_ID
50
+
51
+ if __SESSION is None:
52
+ # determine if clock_skew_in_seconds is a parameter for id_token.verify_oauth2_token()
53
+ try: # PY3
54
+ argspec = inspect.getfullargspec(id_token.verify_oauth2_token)
55
+ except AttributeError: # PY2
56
+ argspec = inspect.getargspec(id_token.verify_oauth2_token)
57
+
58
+ try:
59
+ __SESSION = AuthorizedSession(google.auth.default(['https://www.googleapis.com/auth/userinfo.profile',
60
+ 'https://www.googleapis.com/auth/userinfo.email'])[0])
61
+ health()
62
+ # google.auth 2.1.0 introduced a restrictive clock skew that was unmodifiable until 2.3.2
63
+ if 'clock_skew_in_seconds' in argspec.args:
64
+ __USER_ID = id_token.verify_oauth2_token(__SESSION.credentials.id_token,
65
+ Request(session=__SESSION),
66
+ clock_skew_in_seconds=10)['email']
67
+ else:
68
+ __USER_ID = id_token.verify_oauth2_token(__SESSION.credentials.id_token,
69
+ Request(session=__SESSION))['email']
70
+ except AttributeError:
71
+ __USER_ID = __SESSION.credentials.service_account_email
72
+ except (DefaultCredentialsError, RefreshError) as gae:
73
+ if os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine/'):
74
+ raise
75
+ logging.warning("Unable to determine/refresh application credentials")
76
+ try:
77
+ subprocess.check_call(['gcloud', 'auth', 'application-default',
78
+ 'login', '--no-launch-browser'])
79
+ __SESSION = AuthorizedSession(google.auth.default(['https://www.googleapis.com/auth/userinfo.profile',
80
+ 'https://www.googleapis.com/auth/userinfo.email'])[0])
81
+ except subprocess.CalledProcessError as cpe:
82
+ if cpe.returncode < 0:
83
+ logging.exception("%s was terminated by signal %d",
84
+ cpe.cmd, -cpe.returncode)
85
+ else:
86
+ logging.exception("%s returned %d", cpe.cmd,
87
+ cpe.returncode)
88
+ raise gae
89
+
90
+ def _fiss_agent_header(headers=None):
91
+ """ Return request headers for fiss.
92
+ Inserts FISS as the User-Agent.
93
+ Initializes __SESSION if it hasn't been set.
94
+
95
+ Args:
96
+ headers (dict): Include additional headers as key-value pairs
97
+
98
+ """
99
+ _set_session()
100
+
101
+ fiss_headers = {"User-Agent" : FISS_USER_AGENT}
102
+ if headers is not None:
103
+ fiss_headers.update(headers)
104
+ return fiss_headers
105
+
106
+ def __get(methcall, headers=None, root_url=None, **kwargs):
107
+ if not headers:
108
+ headers = _fiss_agent_header()
109
+ if root_url is None:
110
+ root_url = fcconfig.root_url
111
+ r = __SESSION.get(urljoin(root_url, methcall), headers=headers, **kwargs)
112
+ if fcconfig.verbosity > 1:
113
+ print('FISSFC call: %s' % r.url, file=sys.stderr)
114
+ return r
115
+
116
+ def __patch(methcall, headers=None, root_url=None, **kwargs):
117
+ if not headers:
118
+ headers = _fiss_agent_header({"Content-type": "application/json"})
119
+ if root_url is None:
120
+ root_url = fcconfig.root_url
121
+ r = __SESSION.patch(urljoin(root_url, methcall), headers=headers, **kwargs)
122
+ if fcconfig.verbosity > 1:
123
+ info = r.url
124
+ data = kwargs.get("data", None)
125
+ if data:
126
+ info += " \n(data=%s) " % data
127
+ json = kwargs.get("json", None)
128
+ if json:
129
+ info += " \n(json=%s) " % json
130
+ print('FISSFC call: PATCH %s' % info, file=sys.stderr)
131
+ return r
132
+
133
+ def __post(methcall, headers=None, root_url=None, **kwargs):
134
+ if not headers:
135
+ headers = _fiss_agent_header({"Content-type": "application/json"})
136
+ if root_url is None:
137
+ root_url = fcconfig.root_url
138
+ r = __SESSION.post(urljoin(root_url, methcall), headers=headers, **kwargs)
139
+ if fcconfig.verbosity > 1:
140
+ info = r.url
141
+ json = kwargs.get("json", None)
142
+ if json:
143
+ info += " \n(json=%s) " % json
144
+ print('FISSFC call: POST %s' % info, file=sys.stderr)
145
+ return r
146
+
147
+ def __put(methcall, headers=None, root_url=None, **kwargs):
148
+ if not headers:
149
+ headers = _fiss_agent_header()
150
+ if root_url is None:
151
+ root_url = fcconfig.root_url
152
+ r = __SESSION.put(urljoin(root_url, methcall), headers=headers, **kwargs)
153
+ if fcconfig.verbosity > 1:
154
+ info = r.url
155
+ json = kwargs.get("json", None)
156
+ if json:
157
+ info += " \n(json=%s) " % json
158
+ print('FISSFC call: PUT %s' % info, file=sys.stderr)
159
+ return r
160
+
161
+ def __delete(methcall, headers=None, root_url=None):
162
+ if not headers:
163
+ headers = _fiss_agent_header()
164
+ if root_url is None:
165
+ root_url = fcconfig.root_url
166
+ r = __SESSION.delete(urljoin(root_url, methcall), headers=headers)
167
+ if fcconfig.verbosity > 1:
168
+ print('FISSFC call: DELETE %s' % r.url, file=sys.stderr)
169
+ return r
170
+
171
+ def _check_response_code(response, codes):
172
+ """
173
+ Throws an exception if the http response is not expected. Can check single
174
+ integer or list of valid responses.
175
+
176
+ Example usage:
177
+ >>> r = api.get_workspace("broad-firecloud-testing", "Fake-Bucket")
178
+ >>> _check_response_code(r, 200)
179
+ ... FireCloudServerError ...
180
+ """
181
+ if type(codes) == int:
182
+ codes = [codes]
183
+ if response.status_code not in codes:
184
+ try:
185
+ msg = json.dumps(response.json())
186
+ except:
187
+ msg = response.text
188
+ raise FireCloudServerError(response.status_code, msg)
189
+
190
+ def whoami():
191
+ """ Return __USER_ID """
192
+ _set_session()
193
+ return __USER_ID
194
+
195
+ ##############################################################
196
+ # 1. Orchestration API calls, see https://api.firecloud.org/
197
+ ##############################################################
198
+
199
+ ##################
200
+ ### 1.1 Entities
201
+ ##################
202
+
203
+ def get_entities_with_type(namespace, workspace):
204
+ """List entities in a workspace.
205
+
206
+ Args:
207
+ namespace (str): project to which workspace belongs
208
+ workspace (str): Workspace name
209
+
210
+ Swagger:
211
+ https://api.firecloud.org/#!/Entities/getEntitiesWithType
212
+ """
213
+ uri = "workspaces/{0}/{1}/entities_with_type".format(namespace, workspace)
214
+ return __get(uri)
215
+
216
+ def list_entity_types(namespace, workspace):
217
+ """List the entity types present in a workspace.
218
+
219
+ Args:
220
+ namespace (str): project to which workspace belongs
221
+ workspace (str): Workspace name
222
+
223
+ Swagger:
224
+ https://api.firecloud.org/#!/Entities/getEntityTypes
225
+ """
226
+ headers = _fiss_agent_header({"Content-type": "application/json"})
227
+ uri = "workspaces/{0}/{1}/entities".format(namespace, workspace)
228
+ return __get(uri, headers=headers)
229
+
230
+ def upload_entities(namespace, workspace, entity_data, model='firecloud',
231
+ delete_empty=False):
232
+ """Upload entities from tab-delimited string.
233
+
234
+ Args:
235
+ namespace (str): project to which workspace belongs
236
+ workspace (str): Workspace name
237
+ entity_data (str): TSV string describing entites
238
+ model (str): Data Model type. "firecloud" (default) or "flexible"
239
+ delete_empty (bool): Values left blank in the TSV will be deleted if set to true
240
+
241
+ Swagger:
242
+ https://api.firecloud.org/#!/Entities/importEntities
243
+ https://api.firecloud.org/#!/Entities/flexibleImportEntities
244
+ """
245
+ params = {"deleteEmptyValues": delete_empty}
246
+ body = urlencode({"entities" : entity_data})
247
+ headers = _fiss_agent_header({
248
+ 'Content-type': "application/x-www-form-urlencoded"
249
+ })
250
+ endpoint = 'importEntities'
251
+ if model == 'flexible':
252
+ endpoint = 'flexibleImportEntities'
253
+ uri = "workspaces/{0}/{1}/{2}".format(namespace, workspace, endpoint)
254
+ return __post(uri, headers=headers, data=body, params=params)
255
+
256
+ def upload_entities_tsv(namespace, workspace, entities_tsv, model='firecloud'):
257
+ """Upload entities from a tsv loadfile.
258
+
259
+ File-based wrapper for api.upload_entities().
260
+ A loadfile is a tab-separated text file with a header row
261
+ describing entity type and attribute names, followed by
262
+ rows of entities and their attribute values.
263
+
264
+ Ex:
265
+ entity:participant_id age alive
266
+ participant_23 25 Y
267
+ participant_27 35 N
268
+
269
+ Args:
270
+ namespace (str): project to which workspace belongs
271
+ workspace (str): Workspace name
272
+ entities_tsv (file): FireCloud loadfile, see format above
273
+ model (str): Data Model type. "firecloud" (default) or "flexible"
274
+ """
275
+ if isinstance(entities_tsv, string_types):
276
+ with open(entities_tsv, "r") as tsv:
277
+ entity_data = tsv.read()
278
+ elif isinstance(entities_tsv, io.StringIO):
279
+ entity_data = entities_tsv.getvalue()
280
+ else:
281
+ raise ValueError('Unsupported input type.')
282
+ return upload_entities(namespace, workspace, entity_data, model)
283
+
284
+ def copy_entities(from_namespace, from_workspace, to_namespace,
285
+ to_workspace, etype, enames, link_existing_entities=False):
286
+ """Copy entities between workspaces
287
+
288
+ Args:
289
+ from_namespace (str): project (namespace) to which source workspace belongs
290
+ from_workspace (str): Source workspace name
291
+ to_namespace (str): project (namespace) to which target workspace belongs
292
+ to_workspace (str): Target workspace name
293
+ etype (str): Entity type
294
+ enames (list(str)): List of entity names to copy
295
+ link_existing_entities (boolean): Link all soft conflicts to the entities that already exist.
296
+
297
+ Swagger:
298
+ https://api.firecloud.org/#!/Entities/copyEntities
299
+ """
300
+
301
+ uri = "workspaces/{0}/{1}/entities/copy".format(to_namespace, to_workspace)
302
+ body = {
303
+ "sourceWorkspace": {
304
+ "namespace": from_namespace,
305
+ "name": from_workspace
306
+ },
307
+ "entityType": etype,
308
+ "entityNames": enames
309
+ }
310
+
311
+ return __post(uri, json=body, params={'linkExistingEntities':
312
+ str(link_existing_entities).lower()})
313
+
314
+ def get_entities(namespace, workspace, etype):
315
+ """List entities of given type in a workspace.
316
+
317
+ Response content will be in JSON format.
318
+
319
+ Args:
320
+ namespace (str): project to which workspace belongs
321
+ workspace (str): Workspace name
322
+ etype (str): Entity type
323
+
324
+ Swagger:
325
+ https://api.firecloud.org/#!/Entities/getEntities
326
+ """
327
+ uri = "workspaces/{0}/{1}/entities/{2}".format(namespace, workspace, etype)
328
+ return __get(uri)
329
+
330
+ def get_entities_tsv(namespace, workspace, etype, attrs=None, model="firecloud"):
331
+ """List entities of given type in a workspace as a TSV.
332
+
333
+ Similar to get_entities(), but the response is a TSV.
334
+
335
+ Args:
336
+ namespace (str): project to which workspace belongs
337
+ workspace (str): Workspace name
338
+ etype (str): Entity type
339
+ attrs (list): list of ordered attribute names to be in downloaded tsv
340
+ model (str): Data Model type. "firecloud" (default) or "flexible"
341
+
342
+ Swagger:
343
+ https://api.firecloud.org/#!/Entities/downloadEntitiesTSV
344
+ """
345
+ params = {'model': model}
346
+ if attrs is not None:
347
+ params['attributeNames'] = ','.join(attrs)
348
+ uri = "workspaces/{0}/{1}/entities/{2}/tsv".format(namespace,
349
+ workspace, etype)
350
+ return __get(uri, params=params)
351
+
352
+ def get_entity(namespace, workspace, etype, ename):
353
+ """Request entity information.
354
+
355
+ Gets entity metadata and attributes.
356
+
357
+ Args:
358
+ namespace (str): project to which workspace belongs
359
+ workspace (str): Workspace name
360
+ etype (str): Entity type
361
+ ename (str): The entity's unique id
362
+
363
+ Swagger:
364
+ https://api.firecloud.org/#!/Entities/getEntity
365
+ """
366
+ uri = "workspaces/{0}/{1}/entities/{2}/{3}".format(namespace,
367
+ workspace, etype, ename)
368
+ return __get(uri)
369
+
370
+ def delete_entities(namespace, workspace, json_body):
371
+ """Delete entities in a workspace.
372
+
373
+ Note: This action is not reversible. Be careful!
374
+
375
+ Args:
376
+ namespace (str): project to which workspace belongs
377
+ workspace (str): Workspace name
378
+ json_body:
379
+ [
380
+ {
381
+ "entityType": "string",
382
+ "entityName": "string"
383
+ }
384
+ ]
385
+
386
+ Swagger:
387
+ https://api.firecloud.org/#!/Entities/deleteEntities
388
+ """
389
+
390
+ uri = "workspaces/{0}/{1}/entities/delete".format(namespace, workspace)
391
+ return __post(uri, json=json_body)
392
+
393
+ def delete_entity_type(namespace, workspace, etype, ename):
394
+ """Delete specified entities of a single type in a workspace.
395
+
396
+ Note: This action is not reversible. Be careful!
397
+
398
+ Args:
399
+ namespace (str): project to which workspace belongs
400
+ workspace (str): Workspace name
401
+ etype (str): Entity type
402
+ ename (str, or iterable of str): unique entity id(s)
403
+
404
+ Swagger:
405
+ https://api.firecloud.org/#!/Entities/deleteEntities
406
+ """
407
+
408
+ uri = "workspaces/{0}/{1}/entities/delete".format(namespace, workspace)
409
+ if isinstance(ename, string_types):
410
+ body = [{"entityType":etype, "entityName":ename}]
411
+ elif isinstance(ename, Iterable):
412
+ body = [{"entityType":etype, "entityName":i} for i in ename]
413
+
414
+ return __post(uri, json=body)
415
+
416
+ def delete_entities_of_type(namespace, workspace, etype):
417
+ """Delete all entities of a type in a workspace.
418
+
419
+ Note: This action is not reversible. Be careful!
420
+
421
+ Args:
422
+ namespace (str): project to which workspace belongs
423
+ workspace (str): Workspace name
424
+ etype (str): Entity type
425
+
426
+ Swagger:
427
+ https://api.firecloud.org/#/Entities/deleteEntitiesOfType
428
+ """
429
+
430
+ uri = "workspaces/{0}/{1}/entityTypes/{2}".format(namespace, workspace,
431
+ etype)
432
+ return __delete(uri)
433
+
434
+ def delete_participant(namespace, workspace, name):
435
+ """Delete participant in a workspace.
436
+
437
+ Convenience wrapper for api.delete_entity().
438
+ Note: This action is not reversible. Be careful!
439
+
440
+ Args:
441
+ namespace (str): project to which workspace belongs
442
+ workspace (str): Workspace name
443
+ name (str, or iterable of str): participant_id(s)
444
+ """
445
+ return delete_entity_type(namespace, workspace, "participant", name)
446
+
447
+ def delete_participant_set(namespace, workspace, name):
448
+ """Delete participant set in a workspace.
449
+
450
+ Convenience wrapper for api.delete_entity().
451
+ Note: This action is not reversible. Be careful!
452
+
453
+ Args:
454
+ namespace (str): project to which workspace belongs
455
+ workspace (str): Workspace name
456
+ name (str, or iterable of str): participant_set_id(s)
457
+ """
458
+ return delete_entity_type(namespace, workspace, "participant_set", name)
459
+
460
+ def delete_sample(namespace, workspace, name):
461
+ """Delete sample in a workspace.
462
+
463
+ Convenience wrapper for api.delete_entity().
464
+ Note: This action is not reversible. Be careful!
465
+
466
+ Args:
467
+ namespace (str): project to which workspace belongs
468
+ workspace (str): Workspace name
469
+ name (str, or iterable of str): sample_id(s)
470
+ """
471
+ return delete_entity_type(namespace, workspace, "sample", name)
472
+
473
+ def delete_sample_set(namespace, workspace, name):
474
+ """Delete sample set in a workspace.
475
+
476
+ Convenience wrapper for api.delete_entity().
477
+ Note: This action is not reversible. Be careful!
478
+
479
+ Args:
480
+ namespace (str): project to which workspace belongs
481
+ workspace (str): Workspace name
482
+ name (str, or iterable of str): sample_set_id(s)
483
+ """
484
+ return delete_entity_type(namespace, workspace, "sample_set", name)
485
+
486
+ def delete_pair(namespace, workspace, name):
487
+ """Delete pair in a workspace.
488
+
489
+ Convenience wrapper for api.delete_entity().
490
+ Note: This action is not reversible. Be careful!
491
+
492
+ Args:
493
+ namespace (str): project to which workspace belongs
494
+ workspace (str): Workspace name
495
+ name (str, or iterable of str): pair_id(s)
496
+ """
497
+ return delete_entity_type(namespace, workspace, "pair", name)
498
+
499
+ def delete_pair_set(namespace, workspace, name):
500
+ """Delete pair set in a workspace.
501
+
502
+ Convenience wrapper for api.delete_entity().
503
+ Note: This action is not reversible. Be careful!
504
+
505
+ Args:
506
+ namespace (str): project to which workspace belongs
507
+ workspace (str): Workspace name
508
+ name (str, or iterable of str): pair_set_id(s)
509
+ """
510
+ return delete_entity_type(namespace, workspace, "pair_set", name)
511
+
512
+ def get_entities_query(namespace, workspace, etype, page=1, page_size=100,
513
+ sort_direction="asc", filter_terms=None,
514
+ filter_operator=None, fields=None):
515
+ """Paginated version of get_entities_with_type.
516
+
517
+ Args:
518
+ namespace (str): project to which workspace belongs
519
+ workspace (str): Workspace name
520
+ etype (str): Entity type
521
+ page (int): Page number, 1-indexed
522
+ page_size (int): Number of entities to return per page
523
+ sort_direction (str): "asc" or "desc"
524
+ filter_terms (str): Space-separated list to text match
525
+ filter_operator (str): "and" or "or" - determines if one or all
526
+ filter_terms must have a match. Default: "and"
527
+ fields (str): Comma-separated list of which fields to populate
528
+
529
+ Swagger:
530
+ https://api.firecloud.org/#!/Entities/entityQuery
531
+
532
+ """
533
+
534
+ # Initial parameters for pagination
535
+ params = {
536
+ "page" : page,
537
+ "pageSize" : page_size,
538
+ "sortDirection" : sort_direction
539
+ }
540
+ if filter_terms:
541
+ params['filterTerms'] = filter_terms
542
+ if filter_operator:
543
+ params['filterOperator'] = filter_operator
544
+ if fields:
545
+ params['fields'] = fields
546
+
547
+ uri = "workspaces/{0}/{1}/entityQuery/{2}".format(namespace,workspace,etype)
548
+ return __get(uri, params=params)
549
+
550
+ def rename_entity(namespace, workspace, etype, ename, name):
551
+ """Rename entity in a workspace
552
+
553
+ Args:
554
+ namespace (str): project to which workspace belongs
555
+ workspace (str): Workspace name
556
+ etype (str): Entity type
557
+ ename (str): Entity name
558
+ name (str): New entity name
559
+
560
+ Swagger:
561
+ https://api.firecloud.org/#/Entities/renameEntity
562
+ """
563
+
564
+ body = {"name": name}
565
+ uri = "workspaces/{0}/{1}/entities/{2}/{3}/rename".format(namespace,
566
+ workspace, etype,
567
+ ename)
568
+ return __post(uri, json=body)
569
+
570
+ def rename_entity_type(namespace, workspace, etype, name):
571
+ """Rename entity type in a workspace
572
+
573
+ Args:
574
+ namespace (str): project to which workspace belongs
575
+ workspace (str): Workspace name
576
+ etype (str): Entity type
577
+ name (str): New entity type name
578
+
579
+ Swagger:
580
+ https://api.firecloud.org/#/Entities/renameEntityType
581
+ """
582
+
583
+ body = {"newName": name}
584
+ uri = "workspaces/{0}/{1}/entityTypes/{2}".format(namespace, workspace,
585
+ etype)
586
+ return __patch(uri, json=body)
587
+
588
+ def rename_entity_type_attribute(namespace, workspace, etype, attr, name):
589
+ """Change the attribute name for an entity type in a workspace. If the old
590
+ name doesn't exist the update will fail. If the new name already exists,
591
+ the update will fail, and no records will be updated.
592
+
593
+ Args:
594
+ namespace (str): project to which workspace belongs
595
+ workspace (str): Workspace name
596
+ etype (str): Entity type
597
+ attr (str): Attribute
598
+ name (str): New attribute name
599
+
600
+ Swagger:
601
+ https://api.firecloud.org/#/Entities/rename_entity_attributes
602
+ """
603
+ body = {"newAttributeName": name}
604
+ uri = "workspaces/{0}/{1}/entityTypes/{2}/attributes/{3}".format(namespace,
605
+ workspace,
606
+ etype,
607
+ attr)
608
+ return __patch(uri, json=body)
609
+
610
+ def update_entity(namespace, workspace, etype, ename, updates):
611
+ """ Update entity attributes in a workspace.
612
+
613
+ Args:
614
+ namespace (str): project to which workspace belongs
615
+ workspace (str): Workspace name
616
+ etype (str): Entity type
617
+ ename (str): Entity name
618
+ updates (list(dict)): List of updates to entity from _attr_set, e.g.
619
+
620
+ Swagger:
621
+ https://api.firecloud.org/#!/Entities/update_entity
622
+ """
623
+ headers = _fiss_agent_header({"Content-type": "application/json"})
624
+ uri = "{0}workspaces/{1}/{2}/entities/{3}/{4}".format(fcconfig.root_url,
625
+ namespace, workspace, etype, ename)
626
+
627
+ # FIXME: create __patch method, akin to __get, __delete etc
628
+ return __SESSION.patch(uri, headers=headers, json=updates)
629
+
630
+ ###############################
631
+ ### 1.2 Method Configurations
632
+ ###############################
633
+
634
+ def list_workspace_configs(namespace, workspace, allRepos=False):
635
+ """List method configurations in workspace.
636
+
637
+ Args:
638
+ namespace (str): project to which workspace belongs
639
+ workspace (str): Workspace name
640
+ allRepos (bool): list configs for all repos, not just Agora
641
+
642
+ Swagger:
643
+ https://api.firecloud.org/#!/Method_Configurations/listWorkspaceMethodConfigs
644
+ DUPLICATE: https://api.firecloud.org/#!/Workspaces/listWorkspaceMethodConfigs
645
+ """
646
+ uri = "workspaces/{0}/{1}/methodconfigs".format(namespace, workspace)
647
+ return __get(uri, params={'allRepos': allRepos})
648
+
649
+ def create_workspace_config(namespace, workspace, body):
650
+ """Create method configuration in workspace.
651
+
652
+ Args:
653
+ namespace (str): project to which workspace belongs
654
+ workspace (str): Workspace name
655
+ body (json) : a filled-in JSON object for the new method config
656
+ (e.g. see return value of get_workspace_config)
657
+
658
+ Swagger:
659
+ https://api.firecloud.org/#!/Method_Configurations/postWorkspaceMethodConfig
660
+ DUPLICATE: https://api.firecloud.org/#!/Workspaces/postWorkspaceMethodConfig
661
+ """
662
+
663
+ #json_body = {
664
+ # "namespace" : mnamespace,
665
+ # "name" : method,
666
+ # "rootEntityType" : root_etype,
667
+ # "inputs" : {},
668
+ # "outputs" : {},
669
+ # "prerequisites" : {}
670
+ #}
671
+ uri = "workspaces/{0}/{1}/methodconfigs".format(namespace, workspace)
672
+ return __post(uri, json=body)
673
+
674
+ def delete_workspace_config(namespace, workspace, cnamespace, config):
675
+ """Delete method configuration in workspace.
676
+
677
+ Args:
678
+ namespace (str): project to which workspace belongs
679
+ workspace (str): Workspace name
680
+ mnamespace (str): Method namespace
681
+ method (str): Method name
682
+
683
+ Swagger:
684
+ https://api.firecloud.org/#!/Method_Configurations/deleteWorkspaceMethodConfig
685
+ """
686
+ uri = "workspaces/{0}/{1}/method_configs/{2}/{3}".format(namespace,
687
+ workspace, cnamespace, config)
688
+ return __delete(uri)
689
+
690
+ def get_workspace_config(namespace, workspace, cnamespace, config):
691
+ """Get method configuration in workspace.
692
+
693
+ Args:
694
+ namespace (str): project to which workspace belongs
695
+ workspace (str): Workspace name
696
+ cnamespace (str): Config namespace
697
+ config (str): Config name
698
+
699
+ Swagger:
700
+ https://api.firecloud.org/#!/Method_Configurations/getWorkspaceMethodConfig
701
+ """
702
+
703
+ uri = "workspaces/{0}/{1}/method_configs/{2}/{3}".format(namespace,
704
+ workspace, cnamespace, config)
705
+ return __get(uri)
706
+
707
+ def overwrite_workspace_config(namespace, workspace, cnamespace, configname, body):
708
+ """Add or overwrite method configuration in workspace.
709
+
710
+ Args:
711
+ namespace (str): project to which workspace belongs
712
+ workspace (str): Workspace name
713
+ cnamespace (str): Configuration namespace
714
+ configname (str): Configuration name
715
+ body (json): new body (definition) of the method config
716
+
717
+ Swagger:
718
+ https://api.firecloud.org/#!/Method_Configurations/overwriteWorkspaceMethodConfig
719
+ """
720
+ headers = _fiss_agent_header({"Content-type": "application/json"})
721
+ uri = "workspaces/{0}/{1}/method_configs/{2}/{3}".format(namespace,
722
+ workspace, cnamespace, configname)
723
+ return __put(uri, headers=headers, json=body)
724
+
725
+ def update_workspace_config(namespace, workspace, cnamespace, configname, body):
726
+ """Update method configuration in workspace.
727
+
728
+ Args:
729
+ namespace (str): project to which workspace belongs
730
+ workspace (str): Workspace name
731
+ cnamespace (str): Configuration namespace
732
+ configname (str): Configuration name
733
+ body (json): new body (definition) of the method config
734
+
735
+ Swagger:
736
+ https://api.firecloud.org/#!/Method_Configurations/updateWorkspaceMethodConfig
737
+ """
738
+ uri = "workspaces/{0}/{1}/method_configs/{2}/{3}".format(namespace,
739
+ workspace, cnamespace, configname)
740
+ return __post(uri, json=body)
741
+
742
+ def validate_config(namespace, workspace, cnamespace, config):
743
+ """Get syntax validation for a configuration.
744
+
745
+ Args:
746
+ namespace (str): project to which workspace belongs
747
+ workspace (str): Workspace name
748
+ cnamespace (str): Configuration namespace
749
+ config (str): Configuration name
750
+
751
+ Swagger:
752
+ https://api.firecloud.org/#!/Method_Configurations/validate_method_configuration
753
+ """
754
+ uri = "workspaces/{0}/{1}/method_configs/{2}/{3}/validate".format(namespace,
755
+ workspace, cnamespace, config)
756
+ return __get(uri)
757
+
758
+ def rename_workspace_config(namespace, workspace, cnamespace, config,
759
+ new_namespace, new_name):
760
+ """Rename a method configuration in a workspace.
761
+
762
+ Args:
763
+ namespace (str): project to which workspace belongs
764
+ workspace (str): Workspace name
765
+ mnamespace (str): Config namespace
766
+ config (str): Config name
767
+ new_namespace (str): Updated config namespace
768
+ new_name (str): Updated method name
769
+
770
+ Swagger:
771
+ https://api.firecloud.org/#!/Method_Configurations/renameWorkspaceMethodConfig
772
+ """
773
+
774
+ body = {
775
+ "namespace" : new_namespace,
776
+ "name" : new_name,
777
+ # I have no idea why this is required by FC, but it is...
778
+ "workspaceName" : {
779
+ "namespace" : namespace,
780
+ "name" : workspace
781
+ }
782
+ }
783
+ uri = "workspaces/{0}/{1}/method_configs/{2}/{3}/rename".format(namespace,
784
+ workspace, cnamespace, config)
785
+ return __post(uri, json=body)
786
+
787
+ def copy_config_from_repo(namespace, workspace, from_cnamespace,
788
+ from_config, from_snapshot_id, to_cnamespace,
789
+ to_config):
790
+ """Copy a method config from the methods repository to a workspace.
791
+
792
+ Args:
793
+ namespace (str): project to which workspace belongs
794
+ workspace (str): Workspace name
795
+ from_cnamespace (str): Source configuration namespace
796
+ from_config (str): Source configuration name
797
+ from_snapshot_id (int): Source configuration snapshot_id
798
+ to_cnamespace (str): Target configuration namespace
799
+ to_config (str): Target configuration name
800
+
801
+ Swagger:
802
+ https://api.firecloud.org/#!/Method_Configurations/copyFromMethodRepo
803
+ DUPLICATE: https://api.firecloud.org/#!/Method_Repository/copyFromMethodRepo
804
+ """
805
+
806
+ body = {
807
+ "configurationNamespace" : from_cnamespace,
808
+ "configurationName" : from_config,
809
+ "configurationSnapshotId" : from_snapshot_id,
810
+ "destinationNamespace" : to_cnamespace,
811
+ "destinationName" : to_config
812
+ }
813
+ uri = "workspaces/{0}/{1}/method_configs/copyFromMethodRepo".format(
814
+ namespace, workspace)
815
+ return __post(uri, json=body)
816
+
817
+ def copy_config_to_repo(namespace, workspace, from_cnamespace,
818
+ from_config, to_cnamespace, to_config):
819
+ """Copy a method config from a workspace to the methods repository.
820
+
821
+ Args:
822
+ namespace (str): project to which workspace belongs
823
+ workspace (str): Workspace name
824
+ from_cnamespace (str): Source configuration namespace
825
+ from_config (str): Source configuration name
826
+ to_cnamespace (str): Target configuration namespace
827
+ to_config (str): Target configuration name
828
+
829
+ Swagger:
830
+ https://api.firecloud.org/#!/Method_Configurations/copyToMethodRepo
831
+ DUPLICATE: https://api.firecloud.org/#!/Method_Repository/copyToMethodRepo
832
+ """
833
+
834
+ body = {
835
+ "configurationNamespace" : to_cnamespace,
836
+ "configurationName" : to_config,
837
+ "sourceNamespace" : from_cnamespace,
838
+ "sourceName" : from_config
839
+ }
840
+ uri = "workspaces/{0}/{1}/method_configs/copyToMethodRepo".format(
841
+ namespace, workspace)
842
+ return __post(uri, json=body)
843
+
844
+ ###########################
845
+ ### 1.3 Method Repository
846
+ ###########################
847
+
848
+ def list_repository_methods(namespace=None, name=None, snapshotId=None):
849
+ """List method(s) in the methods repository.
850
+
851
+ Args:
852
+ namespace (str): Method Repository namespace
853
+ name (str): method name
854
+ snapshotId (int): method snapshot ID
855
+
856
+ Swagger:
857
+ https://api.firecloud.org/#!/Method_Repository/listMethodRepositoryMethods
858
+ """
859
+ params = {k:v for (k,v) in locals().items() if v is not None}
860
+ return __get("methods", params=params)
861
+
862
+ def list_repository_configs(namespace=None, name=None, snapshotId=None):
863
+ """List configurations in the methods repository.
864
+
865
+ Args:
866
+ namespace (str): Method Repository namespace
867
+ name (str): config name
868
+ snapshotId (int): config snapshot ID
869
+
870
+ Swagger:
871
+ https://api.firecloud.org/#!/Method_Repository/listMethodRepositoryConfigurations
872
+ """
873
+ params = {k:v for (k,v) in locals().items() if v is not None}
874
+ return __get("configurations", params=params)
875
+
876
+ def get_config_template(namespace, method, version):
877
+ """Get the configuration template for a method.
878
+
879
+ The method should exist in the methods repository.
880
+
881
+ Args:
882
+ namespace (str): Method's namespace
883
+ method (str): method name
884
+ version (int): snapshot_id of the method
885
+
886
+ Swagger:
887
+ https://api.firecloud.org/#!/Method_Repository/createMethodTemplate
888
+ """
889
+
890
+ body = {
891
+ "methodNamespace" : namespace,
892
+ "methodName" : method,
893
+ "methodVersion" : int(version)
894
+ }
895
+ return __post("template", json=body)
896
+
897
+ def get_inputs_outputs(namespace, method, snapshot_id):
898
+ """Get a description of the inputs and outputs for a method.
899
+
900
+ The method should exist in the methods repository.
901
+
902
+ Args:
903
+ namespace (str): Methods namespace
904
+ method (str): method name
905
+ snapshot_id (int): snapshot_id of the method
906
+
907
+ Swagger:
908
+ https://api.firecloud.org/#!/Method_Repository/getMethodIO
909
+ """
910
+
911
+ body = {
912
+ "methodNamespace" : namespace,
913
+ "methodName" : method,
914
+ "methodVersion" : snapshot_id
915
+ }
916
+ return __post("inputsOutputs", json=body)
917
+
918
+ def get_repository_config(namespace, config, snapshot_id):
919
+ """Get a method configuration from the methods repository.
920
+
921
+ Args:
922
+ namespace (str): Methods namespace
923
+ config (str): config name
924
+ snapshot_id (int): snapshot_id of the method
925
+
926
+ Swagger:
927
+ https://api.firecloud.org/#!/Method_Repository/getMethodRepositoryConfiguration
928
+ """
929
+ uri = "configurations/{0}/{1}/{2}".format(namespace, config, snapshot_id)
930
+ return __get(uri)
931
+
932
+ def get_repository_method(namespace, method, snapshot_id, wdl_only=False):
933
+ """Get a method definition from the method repository.
934
+
935
+ Args:
936
+ namespace (str): Methods namespace
937
+ method (str): method name
938
+ version (int): snapshot_id of the method
939
+ wdl_only (bool): Exclude metadata
940
+
941
+ Swagger:
942
+ https://api.firecloud.org/#!/Method_Repository/get_api_methods_namespace_name_snapshotId
943
+ """
944
+ uri = "methods/{0}/{1}/{2}?onlyPayload={3}".format(namespace, method,
945
+ snapshot_id,
946
+ str(wdl_only).lower())
947
+ return __get(uri)
948
+
949
+ def update_repository_method(namespace, method, synopsis, wdl, doc=None,
950
+ comment=""):
951
+ """Create/Update workflow definition.
952
+
953
+ FireCloud will create a new snapshot_id for the given workflow.
954
+
955
+ Args:
956
+ namespace (str): Methods namespace
957
+ method (str): method name
958
+ synopsis (str): short (<80 char) description of method
959
+ wdl (file): Workflow Description Language file
960
+ doc (file): (Optional) Additional documentation
961
+ comment (str): (Optional) Comment specific to this snapshot
962
+
963
+ Swagger:
964
+ https://api.firecloud.org/#!/Method_Repository/post_api_methods
965
+
966
+ """
967
+ with open(wdl, 'r') as wf:
968
+ wdl_payload = wf.read()
969
+ if doc is not None:
970
+ with open (doc, 'r') as df:
971
+ doc = df.read()
972
+
973
+ body = {
974
+ "namespace": namespace,
975
+ "name": method,
976
+ "entityType": "Workflow",
977
+ "payload": wdl_payload,
978
+ "documentation": doc,
979
+ "synopsis": synopsis,
980
+ "snapshotComment": comment
981
+ }
982
+
983
+ return __post("methods",
984
+ json={key: value for key, value in body.items() if value})
985
+
986
+ def delete_repository_method(namespace, name, snapshot_id):
987
+ """Redacts a method and all of its associated configurations.
988
+
989
+ The method should exist in the methods repository.
990
+
991
+ Args:
992
+ namespace (str): Methods namespace
993
+ method (str): method name
994
+ snapshot_id (int): snapshot_id of the method
995
+
996
+ Swagger:
997
+ https://api.firecloud.org/#!/Method_Repository/delete_api_methods_namespace_name_snapshotId
998
+ """
999
+ uri = "methods/{0}/{1}/{2}".format(namespace, name, snapshot_id)
1000
+ return __delete(uri)
1001
+
1002
+ def delete_repository_config(namespace, name, snapshot_id):
1003
+ """Redacts a configuration and all of its associated configurations.
1004
+
1005
+ The configuration should exist in the methods repository.
1006
+
1007
+ Args:
1008
+ namespace (str): configuration namespace
1009
+ configuration (str): configuration name
1010
+ snapshot_id (int): snapshot_id of the configuration
1011
+
1012
+ Swagger:
1013
+ https://api.firecloud.org/#!/Method_Repository/delete_api_configurations_namespace_name_snapshotId
1014
+ """
1015
+ uri = "configurations/{0}/{1}/{2}".format(namespace, name, snapshot_id)
1016
+ return __delete(uri)
1017
+
1018
+ def get_repository_method_acl(namespace, method, snapshot_id):
1019
+ """Get permissions for a method.
1020
+
1021
+ The method should exist in the methods repository.
1022
+
1023
+ Args:
1024
+ namespace (str): Methods namespace
1025
+ method (str): method name
1026
+ version (int): snapshot_id of the method
1027
+
1028
+ Swagger:
1029
+ https://api.firecloud.org/#!/Method_Repository/getMethodACL
1030
+ """
1031
+ uri = "methods/{0}/{1}/{2}/permissions".format(namespace,method,snapshot_id)
1032
+ return __get(uri)
1033
+
1034
+ def update_repository_method_acl(namespace, method, snapshot_id, acl_updates):
1035
+ """Set method permissions.
1036
+
1037
+ The method should exist in the methods repository.
1038
+
1039
+ Args:
1040
+ namespace (str): Methods namespace
1041
+ method (str): method name
1042
+ snapshot_id (int): snapshot_id of the method
1043
+ acl_updates (list(dict)): List of access control updates
1044
+
1045
+ Swagger:
1046
+ https://api.firecloud.org/#!/Method_Repository/setMethodACL
1047
+ """
1048
+
1049
+ uri = "methods/{0}/{1}/{2}/permissions".format(namespace,method,snapshot_id)
1050
+ return __post(uri, json=acl_updates)
1051
+
1052
+ def get_repository_config_acl(namespace, config, snapshot_id):
1053
+ """Get configuration permissions.
1054
+
1055
+ The configuration should exist in the methods repository.
1056
+
1057
+ Args:
1058
+ namespace (str): Configuration namespace
1059
+ config (str): Configuration name
1060
+ snapshot_id (int): snapshot_id of the method
1061
+
1062
+ Swagger:
1063
+ https://api.firecloud.org/#!/Method_Repository/getConfigACL
1064
+ """
1065
+ uri = "configurations/{0}/{1}/{2}/permissions".format(namespace,
1066
+ config, snapshot_id)
1067
+ return __get(uri)
1068
+
1069
+ def update_repository_config_acl(namespace, config, snapshot_id, acl_updates):
1070
+ """Set configuration permissions.
1071
+
1072
+ The configuration should exist in the methods repository.
1073
+
1074
+ Args:
1075
+ namespace (str): Configuration namespace
1076
+ config (str): Configuration name
1077
+ snapshot_id (int): snapshot_id of the method
1078
+ acl_updates (list(dict)): List of access control updates
1079
+
1080
+ Swagger:
1081
+ https://api.firecloud.org/#!/Method_Repository/setConfigACL
1082
+ """
1083
+
1084
+ uri = "configurations/{0}/{1}/{2}/permissions".format(namespace,
1085
+ config, snapshot_id)
1086
+ return __post(uri, json=acl_updates)
1087
+
1088
+ def get_method_configurations(namespace, method_name):
1089
+ """Get method configurations.
1090
+
1091
+ Given the namespace/name of a method, returns all configurations in
1092
+ the repository that reference that method.
1093
+
1094
+ Args:
1095
+ namespace (str): Method namespace
1096
+ method_name (str): Method name
1097
+
1098
+ Swagger:
1099
+ https://api.firecloud.org/#!/Method_Repository/get_api_methods_namespace_name_configurations
1100
+
1101
+ """
1102
+
1103
+ uri = "methods/{0}/{1}/configurations".format(namespace, method_name)
1104
+
1105
+ return __get(uri)
1106
+
1107
+ def get_api_methods_definitions():
1108
+ """List method definitions.
1109
+
1110
+ List method definitions - i.e. unique namespace/name pairs -
1111
+ with counts of snapshots and associated configurations
1112
+
1113
+ Swagger:
1114
+ https://api.firecloud.org/#!/Method_Repository/get_api_methods_definitions
1115
+
1116
+ """
1117
+
1118
+ uri = "methods/definitions"
1119
+
1120
+ return __get(uri)
1121
+
1122
+
1123
+ #################
1124
+ ### 1.4 Profile
1125
+ #################
1126
+
1127
+ def list_billing_projects():
1128
+ """list billing projects for a user.
1129
+
1130
+ Swagger:
1131
+ https://api.firecloud.org/#/BillingV2/listUserBillingProjectsV2
1132
+ """
1133
+ return __get("billing/v2")
1134
+
1135
+ def get_proxy_group(email=None):
1136
+ """Returns the proxy group email for the current user
1137
+
1138
+ Args:
1139
+ email (str): User email whose proxy group to retrieve
1140
+ if None uses current user email
1141
+
1142
+ Swagger:
1143
+ https://api.firecloud.org/#/Profile/getProxyGroup
1144
+ """
1145
+ if email is None:
1146
+ email = whoami()
1147
+ uri = "proxyGroup/{}".format(email)
1148
+ return __get(uri)
1149
+
1150
+ ################
1151
+ ### 1.5 Status
1152
+ ################
1153
+
1154
+ def get_status():
1155
+ """Request the status of FireCloud services.
1156
+
1157
+ Swagger:
1158
+ https://api.firecloud.org/#!/Status/status
1159
+ """
1160
+ root_url = fcconfig.root_url.rpartition("api")[0]
1161
+ return __get("status", root_url=root_url)
1162
+
1163
+ def health():
1164
+ """Health of FireCloud API.
1165
+
1166
+ Swagger:
1167
+ https://api.firecloud.org/#!/Status/health
1168
+ """
1169
+ root_url = fcconfig.root_url.rpartition("api")[0]
1170
+ return __get("health", root_url=root_url)
1171
+
1172
+ ######################
1173
+ ### 1.6 Submissions
1174
+ ######################
1175
+
1176
+ def list_submissions(namespace, workspace):
1177
+ """List submissions in FireCloud workspace.
1178
+
1179
+ Args:
1180
+ namespace (str): project to which workspace belongs
1181
+ workspace (str): Workspace name
1182
+
1183
+ Swagger:
1184
+ https://api.firecloud.org/#!/Submissions/listSubmissions
1185
+ """
1186
+ uri = "workspaces/{0}/{1}/submissions".format(namespace, workspace)
1187
+ return __get(uri)
1188
+
1189
+ def create_submission(wnamespace, workspace, cnamespace, config,
1190
+ entity=None, etype=None, expression=None,
1191
+ use_callcache=True, delete_intermediate_output_files=False,
1192
+ use_reference_disks=False, memory_retry_multiplier=0,
1193
+ per_workflow_cost_cap=None, workflow_failure_mode="",
1194
+ user_comment=""):
1195
+ """Submit job in FireCloud workspace.
1196
+
1197
+ Args:
1198
+ wnamespace (str): project to which workspace belongs
1199
+ workspace (str): Workspace name
1200
+ cnamespace (str): Method configuration namespace
1201
+ config (str): Method configuration name
1202
+ entity (str): Entity to submit job on. Should be the same type as
1203
+ the root entity type of the method config, unless an
1204
+ expression is used
1205
+ etype (str): Entity type of root_entity
1206
+ expression (str): Instead of using entity as the root entity,
1207
+ evaluate the root entity from this expression.
1208
+ use_callcache (bool): use call cache if applicable (default: true)
1209
+ delete_intermediate_output_files (bool): Whether or not to delete
1210
+ intermediate output files when the workflow completes. See Cromwell
1211
+ docs (https://cromwell.readthedocs.io/en/develop/wf_options/Google)
1212
+ for more information
1213
+ use_reference_disks (bool): Whether or not to use pre-built disks for
1214
+ common genome references
1215
+ memory_retry_multiplier (float): If a task fails due to running out of
1216
+ memory and the task has maxRetries in its runtime attributes, then
1217
+ it will be retried with its memory multiplied by this amount. See
1218
+ Cromwell docs
1219
+ (https://cromwell.readthedocs.io/en/develop/cromwell_features/RetryWithMoreMemory)
1220
+ for more information
1221
+ per_workflow_cost_cap (float): A cost threshold in USD to apply to individual
1222
+ workflows. When the estimated cost is exceeded, the workflow is terminated.
1223
+ workflow_failure_mode (str): What happens after a task fails. Choose from
1224
+ ContinueWhilePossible and NoNewCalls. Defaults to NoNewCalls if not
1225
+ specified. See Cromwell docs
1226
+ (https://cromwell.readthedocs.io/en/develop/execution/ExecutionTwists/#failure-modes)
1227
+ for more information.
1228
+ user_comment: Freeform user defined description, optional (max length
1229
+ 1000 characters)
1230
+
1231
+ Swagger:
1232
+ https://api.firecloud.org/#!/Submissions/createSubmission
1233
+ """
1234
+
1235
+ uri = "workspaces/{0}/{1}/submissions".format(wnamespace, workspace)
1236
+ body = {
1237
+ "methodConfigurationNamespace" : cnamespace,
1238
+ "methodConfigurationName" : config,
1239
+ "useCallCache" : use_callcache
1240
+ }
1241
+
1242
+ if etype:
1243
+ body['entityType'] = etype
1244
+
1245
+ if entity:
1246
+ body['entityName'] = entity
1247
+
1248
+ if expression:
1249
+ body['expression'] = expression
1250
+
1251
+ if delete_intermediate_output_files:
1252
+ body['deleteIntermediateOutputFiles'] = delete_intermediate_output_files
1253
+
1254
+ if use_reference_disks:
1255
+ body['useReferenceDisks'] = use_reference_disks
1256
+
1257
+ if memory_retry_multiplier:
1258
+ body['memoryRetryMultiplier'] = memory_retry_multiplier
1259
+
1260
+ if per_workflow_cost_cap:
1261
+ body['perWorkflowCostCap'] = per_workflow_cost_cap
1262
+
1263
+ if workflow_failure_mode:
1264
+ body['workflowFailureMode'] = workflow_failure_mode
1265
+
1266
+ if user_comment:
1267
+ body['userComment'] = user_comment
1268
+
1269
+ return __post(uri, json=body)
1270
+
1271
+ def abort_submission(namespace, workspace, submission_id):
1272
+ """Abort running job in a workspace.
1273
+
1274
+ Args:
1275
+ namespace (str): project to which workspace belongs
1276
+ workspace (str): Workspace name
1277
+ submission_id (str): Submission's unique identifier
1278
+
1279
+ Swagger:
1280
+ https://api.firecloud.org/#!/Submissions/deleteSubmission
1281
+ """
1282
+ uri = "workspaces/{0}/{1}/submissions/{2}".format(namespace,
1283
+ workspace, submission_id)
1284
+ return __delete(uri)
1285
+
1286
+ def get_submission(namespace, workspace, submission_id):
1287
+ """Request submission information.
1288
+
1289
+ Args:
1290
+ namespace (str): project to which workspace belongs
1291
+ workspace (str): Workspace name
1292
+ submission_id (str): Submission's unique identifier
1293
+
1294
+ Swagger:
1295
+ https://api.firecloud.org/#!/Submissions/monitorSubmission
1296
+ """
1297
+ uri = "workspaces/{0}/{1}/submissions/{2}".format(namespace,
1298
+ workspace, submission_id)
1299
+ return __get(uri)
1300
+
1301
+ def get_workflow_metadata(namespace, workspace, submission_id, workflow_id,
1302
+ include_key=None, exclude_key=None,
1303
+ expand_sub_workflows=False):
1304
+ """Request the metadata for a workflow in a submission.
1305
+
1306
+ Args:
1307
+ namespace (str): project to which workspace belongs
1308
+ workspace (str): Workspace name
1309
+ submission_id (str): Submission's unique identifier
1310
+ workflow_id (str): Workflow's unique identifier.
1311
+ include_key (array[str]): When specified, return only these keys in the
1312
+ response. Matches any key in the response, including within nested
1313
+ blocks. May not be used with exclude_key.
1314
+ exclude_key (array[str]): When specified, omit these keys from the
1315
+ response. Matches any key in the response, including within nested
1316
+ blocks. May not be used with include_key.
1317
+ expand_sub_workflows (bool): When true, metadata for sub workflows will
1318
+ be fetched and inserted automatically in the metadata response.
1319
+
1320
+ Swagger:
1321
+ https://api.firecloud.org/#!/Submissions/workflowMetadata
1322
+ """
1323
+ uri = "workspaces/{0}/{1}/submissions/{2}/workflows/{3}".format(namespace,
1324
+ workspace, submission_id, workflow_id)
1325
+ params = {}
1326
+ if include_key is not None:
1327
+ params["includeKey"] = include_key
1328
+ if exclude_key is not None:
1329
+ params["excludeKey"] = exclude_key
1330
+ if expand_sub_workflows:
1331
+ params["expandSubWorkflows"] = expand_sub_workflows
1332
+ return __get(uri, params=params)
1333
+
1334
+ def get_workflow_outputs(namespace, workspace, submission_id, workflow_id):
1335
+ """Request the outputs for a workflow in a submission.
1336
+
1337
+ Args:
1338
+ namespace (str): project to which workspace belongs
1339
+ workspace (str): Workspace name
1340
+ submission_id (str): Submission's unique identifier
1341
+ workflow_id (str): Workflow's unique identifier.
1342
+
1343
+ Swagger:
1344
+ https://api.firecloud.org/#!/Submissions/workflowOutputsInSubmission
1345
+ """
1346
+ uri = "workspaces/{0}/{1}/".format(namespace, workspace)
1347
+ uri += "submissions/{0}/workflows/{1}/outputs".format(submission_id,
1348
+ workflow_id)
1349
+ return __get(uri)
1350
+
1351
+ def get_workflow_cost(namespace, workspace, submission_id, workflow_id):
1352
+ """Request the cost for a workflow in a submission.
1353
+
1354
+ Args:
1355
+ namespace (str): project to which workspace belongs
1356
+ workspace (str): Workspace name
1357
+ submission_id (str): Submission's unique identifier
1358
+ workflow_id (str): Workflow's unique identifier.
1359
+
1360
+ Swagger:
1361
+ https://api.firecloud.org/#!/Submissions/workflowCostInSubmission
1362
+ """
1363
+ uri = "workspaces/{0}/{1}/".format(namespace, workspace)
1364
+ uri += "submissions/{0}/workflows/{1}/cost".format(submission_id,
1365
+ workflow_id)
1366
+ return __get(uri)
1367
+
1368
+ def get_submission_queue():
1369
+ """ List workflow counts by queueing state.
1370
+
1371
+ Swagger:
1372
+ https://api.firecloud.org/#!/Submissions/workflowQueueStatus
1373
+ """
1374
+ return __get("submissions/queueStatus")
1375
+
1376
+ #####################
1377
+ ### 1.7 Workspaces
1378
+ #####################
1379
+
1380
+ def list_workspaces(fields=None):
1381
+ """Request list of FireCloud workspaces.
1382
+
1383
+ Args:
1384
+ fields (str): a comma-delimited list of values that limits the
1385
+ response payload to include only those keys and exclude other
1386
+ keys (e.g., to include {"workspace": {"attributes": {...}}},
1387
+ specify "workspace.attributes").
1388
+
1389
+ Swagger:
1390
+ https://api.firecloud.org/#!/Workspaces/listWorkspaces
1391
+ """
1392
+ if fields is None:
1393
+ return __get("workspaces")
1394
+ else:
1395
+ return __get("workspaces", params={"fields": fields})
1396
+
1397
+ def get_storage_cost(namespace, workspace):
1398
+ """Request average monthly storage cost for workspace.
1399
+ Args:
1400
+ namespace (str): project to which workspace belongs
1401
+ workspace (str): Workspace name
1402
+ Swagger:
1403
+ https://api.firecloud.org/#/WorkspacesV2/getStorageCostEstimateV2
1404
+ """
1405
+ uri = "workspaces/v2/{0}/{1}/storageCostEstimate".format(namespace, workspace)
1406
+ return __get(uri)
1407
+
1408
+ def get_bucket_usage(namespace, workspace):
1409
+ """Request google bucket usage for workspace.
1410
+ Args:
1411
+ namespace (str): project to which workspace belongs
1412
+ workspace (str): Workspace name
1413
+ """
1414
+ return get_storage_cost(namespace, workspace)
1415
+
1416
+ def create_workspace(namespace, name, authorizationDomain="", attributes=None,
1417
+ noWorkspaceOwner=False, bucketLocation=""):
1418
+ """Create a new FireCloud Workspace.
1419
+
1420
+ Args:
1421
+ namespace (str): The namespace (billing project) the workspace belongs to
1422
+ name (str): The name of the workspace
1423
+ authorizationDomain (str|list): The list of groups in the Authorization
1424
+ Domain (empty if no AD is set)
1425
+ attributes (dict): Workspace attributes as key value pairs
1426
+ noWorkspaceOwner (bool): Optional, false if not specified. If true, the
1427
+ workspace is created with a Billing Project
1428
+ owner but no workspace owner. Requires being a
1429
+ Billing Project owner.
1430
+ bucketLocation (str): Region (NOT multi-region) in which bucket
1431
+ attached to the workspace should be created. If
1432
+ not provided, the bucket will be created in the
1433
+ 'US' multi-region.
1434
+
1435
+ Swagger:
1436
+ https://api.firecloud.org/#!/Workspaces/createWorkspace
1437
+ """
1438
+
1439
+ if not attributes:
1440
+ attributes = dict()
1441
+
1442
+ body = {
1443
+ "namespace": namespace,
1444
+ "name": name,
1445
+ "attributes": attributes
1446
+ }
1447
+
1448
+ if authorizationDomain:
1449
+ if isinstance(authorizationDomain, string_types):
1450
+ authDomain = [{"membersGroupName": authorizationDomain}]
1451
+ else:
1452
+ authDomain = [{"membersGroupName": groupName} for groupName in authorizationDomain]
1453
+ else:
1454
+ authDomain = []
1455
+
1456
+ body["authorizationDomain"] = authDomain
1457
+
1458
+ if noWorkspaceOwner:
1459
+ body["noWorkspaceOwner"] = noWorkspaceOwner
1460
+
1461
+ if bucketLocation:
1462
+ body["bucketLocation"] = bucketLocation
1463
+
1464
+ return __post("workspaces", json=body)
1465
+
1466
+ def delete_workspace(namespace, workspace):
1467
+ """Delete FireCloud Workspace.
1468
+
1469
+ Note: This action is not reversible. Be careful!
1470
+
1471
+ Args:
1472
+ namespace (str): project to which workspace belongs
1473
+ workspace (str): Workspace name
1474
+
1475
+ Swagger:
1476
+ https://api.firecloud.org/#!/Workspaces/deleteWorkspace
1477
+ """
1478
+ uri = "workspaces/{0}/{1}".format(namespace, workspace)
1479
+ return __delete(uri)
1480
+
1481
+ def get_workspace(namespace, workspace, fields=None):
1482
+ """Request FireCloud Workspace information.
1483
+
1484
+ Args:
1485
+ namespace (str): project to which workspace belongs
1486
+ workspace (str): Workspace name
1487
+ fields (str): a comma-delimited list of values that limits the
1488
+ response payload to include only those keys and exclude other
1489
+ keys (e.g., to include {"workspace": {"attributes": {...}}},
1490
+ specify "workspace.attributes").
1491
+
1492
+ Swagger:
1493
+ https://api.firecloud.org/#!/Workspaces/getWorkspace
1494
+ """
1495
+ uri = "workspaces/{0}/{1}".format(namespace, workspace)
1496
+ if fields is None:
1497
+ return __get(uri)
1498
+ else:
1499
+ return __get(uri, params={"fields": fields})
1500
+
1501
+ def get_workspace_acl(namespace, workspace):
1502
+ """Request FireCloud access aontrol list for workspace.
1503
+
1504
+ Args:
1505
+ namespace (str): project to which workspace belongs
1506
+ workspace (str): Workspace name
1507
+
1508
+ Swagger:
1509
+ https://api.firecloud.org/#!/Workspaces/getWorkspaceAcl
1510
+ """
1511
+ uri = "workspaces/{0}/{1}/acl".format(namespace, workspace)
1512
+ return __get(uri)
1513
+
1514
+ def update_workspace_acl(namespace, workspace, acl_updates, invite_users_not_found=False):
1515
+ """Update workspace access control list.
1516
+
1517
+ Args:
1518
+ namespace (str): project to which workspace belongs
1519
+ workspace (str): Workspace name
1520
+ acl_updates (list(dict)): Acl updates as dicts with two keys:
1521
+ "email" - Firecloud user email
1522
+ "accessLevel" - one of "OWNER", "READER", "WRITER", "NO ACCESS"
1523
+ Example: {"email":"user1@mail.com", "accessLevel":"WRITER"}
1524
+ invite_users_not_found (bool): true to invite unregistered users, false to ignore
1525
+
1526
+ Swagger:
1527
+ https://api.firecloud.org/#!/Workspaces/updateWorkspaceACL
1528
+ """
1529
+ uri = "{0}workspaces/{1}/{2}/acl?inviteUsersNotFound={3}".format(fcconfig.root_url,
1530
+ namespace, workspace, str(invite_users_not_found).lower())
1531
+ headers = _fiss_agent_header({"Content-type": "application/json"})
1532
+ # FIXME: create __patch method, akin to __get, __delete etc
1533
+ return __SESSION.patch(uri, headers=headers, data=json.dumps(acl_updates))
1534
+
1535
+ def clone_workspace(from_namespace, from_workspace, to_namespace, to_workspace,
1536
+ authorizationDomain="", copyFilesWithPrefix=None, bucketLocation=None):
1537
+ """Clone a FireCloud workspace.
1538
+
1539
+ A clone is a shallow copy of a FireCloud workspace, enabling
1540
+ easy sharing of data, such as TCGA data, without duplication.
1541
+
1542
+ Args:
1543
+ from_namespace (str): project (namespace) to which source workspace belongs
1544
+ from_workspace (str): Source workspace's name
1545
+ to_namespace (str): project to which target workspace belongs
1546
+ to_workspace (str): Target workspace's name
1547
+ authorizationDomain: (str) required authorization domains
1548
+ copyFilesWithPrefix: (str) prefix of bucket objects to copy to the destination workspace
1549
+
1550
+ Swagger:
1551
+ https://api.firecloud.org/#!/Workspaces/cloneWorkspace
1552
+ """
1553
+
1554
+ if authorizationDomain:
1555
+ if isinstance(authorizationDomain, string_types):
1556
+ authDomain = [{"membersGroupName": authorizationDomain}]
1557
+ else:
1558
+ authDomain = [{"membersGroupName": authDomain} for authDomain in authorizationDomain]
1559
+ else:
1560
+ authDomain = []
1561
+
1562
+ body = {
1563
+ "namespace": to_namespace,
1564
+ "name": to_workspace,
1565
+ "attributes": dict(),
1566
+ "authorizationDomain": authDomain,
1567
+ }
1568
+
1569
+ if copyFilesWithPrefix is not None:
1570
+ body["copyFilesWithPrefix"] = copyFilesWithPrefix
1571
+ if bucketLocation is not None:
1572
+ body["bucketLocation"] = bucketLocation
1573
+
1574
+ uri = "workspaces/{0}/{1}/clone".format(from_namespace, from_workspace)
1575
+ return __post(uri, json=body)
1576
+
1577
+ def lock_workspace(namespace, workspace):
1578
+ """Lock FireCloud workspace, making it read-only.
1579
+
1580
+ This prevents modifying attributes or submitting workflows
1581
+ in the workspace. Can be undone with unlock_workspace()
1582
+
1583
+ Args:
1584
+ namespace (str): project to which workspace belongs
1585
+ workspace (str): Workspace name
1586
+
1587
+ Swagger:
1588
+ https://api.firecloud.org/#!/Workspaces/lockWorkspace
1589
+ """
1590
+ uri = "workspaces/{0}/{1}/lock".format(namespace, workspace)
1591
+ return __put(uri)
1592
+
1593
+ def unlock_workspace(namespace, workspace):
1594
+ """Unlock FireCloud workspace.
1595
+
1596
+ Enables modifications to a workspace. See lock_workspace()
1597
+
1598
+ Args:
1599
+ namespace (str): project to which workspace belongs
1600
+ workspace (str): Workspace name
1601
+
1602
+ Swagger:
1603
+ https://api.firecloud.org/#!/Workspaces/unlockWorkspace
1604
+ """
1605
+ uri = "workspaces/{0}/{1}/unlock".format(namespace, workspace)
1606
+ return __put(uri)
1607
+
1608
+ def update_workspace_attributes(namespace, workspace, attrs):
1609
+ """Update or remove workspace attributes.
1610
+
1611
+ Args:
1612
+ namespace (str): project to which workspace belongs
1613
+ workspace (str): Workspace name
1614
+ attrs (list(dict)): List of update operations for workspace attributes.
1615
+ Use the helper dictionary construction functions to create these:
1616
+
1617
+ _attr_set() : Set/Update attribute
1618
+ _attr_rem() : Remove attribute
1619
+ _attr_ladd() : Add member to list attribute
1620
+ _attr_lrem() : Remove member from list attribute
1621
+ _attr_vlcreate() : Create a value-list attribute
1622
+ _attr_erlcreate() : Create an entity-reference list attribute
1623
+
1624
+ Swagger:
1625
+ https://api.firecloud.org/#!/Workspaces/updateAttributes
1626
+ """
1627
+ headers = _fiss_agent_header({"Content-type": "application/json"})
1628
+ uri = "{0}workspaces/{1}/{2}/updateAttributes".format(fcconfig.root_url,
1629
+ namespace, workspace)
1630
+ body = json.dumps(attrs)
1631
+
1632
+ # FIXME: create __patch method, akin to __get, __delete etc
1633
+ return __SESSION.patch(uri, headers=headers, data=body)
1634
+
1635
+ # Helper functions to create attribute update dictionaries
1636
+
1637
+ def _attr_set(attr, value):
1638
+ """Create an 'update' dictionary for update_workspace_attributes() and
1639
+ update_entity()"""
1640
+ return {
1641
+ "op" : "AddUpdateAttribute",
1642
+ "attributeName" : attr,
1643
+ "addUpdateAttribute" : value
1644
+ }
1645
+
1646
+ def _attr_rem(attr):
1647
+ """Create a 'remove' dictionary for update_workspace_attributes() and
1648
+ update_entity()"""
1649
+ return {
1650
+ "op" : "RemoveAttribute",
1651
+ "attributeName" : attr
1652
+ }
1653
+
1654
+ def _attr_ladd(attr, value):
1655
+ """Create a 'list add' dictionary for update_workspace_attributes() and
1656
+ update_entity()"""
1657
+ return {
1658
+ "op" : "AddListMember",
1659
+ "attributeListName" : attr,
1660
+ "newMember" : value
1661
+ }
1662
+
1663
+ def _attr_lrem(attr, value):
1664
+ """Create a 'list remove' dictionary for update_workspace_attributes() and
1665
+ update_entity()"""
1666
+ return {
1667
+ "op" : "RemoveListMember",
1668
+ "attributeListName" : attr,
1669
+ "removeMember" : value,
1670
+ }
1671
+
1672
+ def _attr_vlcreate(attr):
1673
+ """Create a 'value-list create' dict for update_workspace_attributes() and
1674
+ update_entity()"""
1675
+ return {
1676
+ "op" : "CreateAttributeValueList",
1677
+ "attributeName" : attr
1678
+ }
1679
+
1680
+ def _attr_erlcreate(attr):
1681
+ """Create a 'entity-reference list create' dictionary for
1682
+ update_workspace_attributes() and update_entity()"""
1683
+ return {
1684
+ "op" : "CreateAttributeEntityReferenceList",
1685
+ "attributeListName" : attr
1686
+ }
1687
+
1688
+ #####################
1689
+ ### 1.8 Groups
1690
+ #####################
1691
+
1692
+ def get_groups():
1693
+ """Get the list of the groups that the caller is a member of
1694
+
1695
+ Swagger:
1696
+ https://api.firecloud.org/#!/Groups/getGroups
1697
+ """
1698
+ return __get('groups')
1699
+
1700
+ def get_group(group):
1701
+ """View the members in a group (must be an Admin of the group)
1702
+
1703
+ Args:
1704
+ group (str): Group name
1705
+
1706
+ Swagger:
1707
+ https://api.firecloud.org/#!/Groups/getGroup
1708
+ """
1709
+ uri = "groups/{0}".format(group)
1710
+ return __get(uri)
1711
+
1712
+ def delete_group(group):
1713
+ """Delete a group that the caller owns
1714
+
1715
+ Args:
1716
+ group (str): Group name
1717
+
1718
+ Swagger:
1719
+ https://api.firecloud.org/#!/Groups/deleteGroup
1720
+ """
1721
+ uri = "groups/{0}".format(group)
1722
+ return __delete(uri)
1723
+
1724
+ def create_group(group):
1725
+ """Create a new group
1726
+
1727
+ Args:
1728
+ group (str): Group name
1729
+
1730
+ Swagger:
1731
+ https://api.firecloud.org/#!/Groups/createGroup
1732
+ """
1733
+ uri = "groups/{0}".format(group)
1734
+ return __post(uri)
1735
+
1736
+ def add_user_to_group(group, role, email):
1737
+ """Add a user to a group the caller owns
1738
+
1739
+ Args:
1740
+ group (str): Group name
1741
+ role (str) : Role of user for group; either 'member' or 'admin'
1742
+ email (str): Email of user or group to add
1743
+
1744
+ Swagger:
1745
+ https://api.firecloud.org/#!/Groups/addUserToGroup
1746
+ """
1747
+ uri = "groups/{0}/{1}/{2}".format(group, role, email)
1748
+ return __put(uri)
1749
+
1750
+ def remove_user_from_group(group, role, email):
1751
+ """Remove a user from a group the caller owns
1752
+
1753
+ Args:
1754
+ group (str): Group name
1755
+ role (str) : Role of user for group; either 'member' or 'admin'
1756
+ email (str): Email of user or group to remove
1757
+
1758
+ Swagger:
1759
+ https://api.firecloud.org/#!/Groups/removeUserFromGroup
1760
+ """
1761
+ uri = "groups/{0}/{1}/{2}".format(group, role, email)
1762
+ return __delete(uri)
1763
+
1764
+ def request_access_to_group(group):
1765
+ """Request access to a group
1766
+
1767
+ Args:
1768
+ group (str): Group name
1769
+
1770
+ Swagger:
1771
+ https://api.firecloud.org/#!/Groups/requestAccessToGroup
1772
+ """
1773
+ uri = "groups/{0}/requestAccess".format(group)
1774
+ return __post(uri)