seqslab-cli 3.2.6__tar.gz → 3.2.7__tar.gz

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.
Files changed (109) hide show
  1. {seqslab-cli-3.2.6/python/seqslab_cli.egg-info → seqslab-cli-3.2.7}/PKG-INFO +1 -1
  2. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/__init__.py +1 -1
  3. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/cli.py +2 -2
  4. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/api/base.py +17 -0
  5. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/commands.py +28 -0
  6. seqslab-cli-3.2.7/python/seqslab/scr/__init__.py +15 -0
  7. seqslab-cli-3.2.7/python/seqslab/scr/commands.py +209 -0
  8. seqslab-cli-3.2.7/python/seqslab/scr/internal/common.py +46 -0
  9. seqslab-cli-3.2.7/python/seqslab/scr/resource/base.py +124 -0
  10. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/settings.py +4 -0
  11. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/commands.py +19 -9
  12. {seqslab-cli-3.2.6/python/seqslab/wes → seqslab-cli-3.2.7/python/seqslab/trs}/resource/azure.py +2 -2
  13. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/resource/base.py +9 -28
  14. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/resource/common.py +2 -2
  15. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/template/base.py +2 -2
  16. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/workspace/commands.py +0 -33
  17. seqslab-cli-3.2.7/python/seqslab/workspace/internal/__init__.py +0 -0
  18. seqslab-cli-3.2.7/python/seqslab/workspace/resource/__init__.py +0 -0
  19. seqslab-cli-3.2.7/python/seqslab/workspace/resource/azure.py +25 -0
  20. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/workspace/resource/base.py +1 -15
  21. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7/python/seqslab_cli.egg-info}/PKG-INFO +1 -1
  22. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab_cli.egg-info/SOURCES.txt +7 -1
  23. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab_cli.egg-info/requires.txt +8 -8
  24. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/requirements.txt +8 -8
  25. seqslab-cli-3.2.6/python/seqslab/wes/utils.py +0 -102
  26. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/LICENSE +0 -0
  27. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/MANIFEST.in +0 -0
  28. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/README.md +0 -0
  29. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/auth/__init__.py +0 -0
  30. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/auth/azuread.py +0 -0
  31. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/auth/commands.py +0 -0
  32. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/context.py +0 -0
  33. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/__init__.py +0 -0
  34. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/api/__init__.py +0 -0
  35. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/api/azure.py +0 -0
  36. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/api/common.py +0 -0
  37. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/api/template.py +0 -0
  38. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/internal/__init__.py +0 -0
  39. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/internal/aiocopy.py +0 -0
  40. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/internal/common.py +0 -0
  41. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/internal/utils.py +0 -0
  42. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/storage/__init__.py +0 -0
  43. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/storage/azure.py +0 -0
  44. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/storage/base.py +0 -0
  45. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/utils/__init__.py +0 -0
  46. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/utils/atgxmetadata.py +0 -0
  47. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/utils/biomimetype.py +0 -0
  48. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/drs/utils/progressbar.py +0 -0
  49. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/exceptions.py +0 -0
  50. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/organization/__init__.py +0 -0
  51. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/organization/commands.py +0 -0
  52. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/organization/resource/__init__.py +0 -0
  53. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/organization/resource/base.py +0 -0
  54. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/plugin.py +0 -0
  55. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/__init__.py +0 -0
  56. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/commands.py +0 -0
  57. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/internal/__init__.py +0 -0
  58. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/internal/common.py +0 -0
  59. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/resource/__init__.py +0 -0
  60. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/resource/azure.py +0 -0
  61. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/role/resource/base.py +0 -0
  62. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/runsheet/__init__.py +0 -0
  63. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/runsheet/runsheet.py +0 -0
  64. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/sample_sheet/__init__.py +0 -0
  65. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/sample_sheet/_version.py +0 -0
  66. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/sample_sheet/util.py +0 -0
  67. {seqslab-cli-3.2.6/python/seqslab/trs → seqslab-cli-3.2.7/python/seqslab/scr}/internal/__init__.py +0 -0
  68. {seqslab-cli-3.2.6/python/seqslab/trs/register → seqslab-cli-3.2.7/python/seqslab/scr/resource}/__init__.py +0 -0
  69. {seqslab-cli-3.2.6/python/seqslab/workspace → seqslab-cli-3.2.7/python/seqslab/scr}/resource/azure.py +0 -0
  70. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/session_logger.py +0 -0
  71. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/statusbar.py +0 -0
  72. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/__init__.py +0 -0
  73. {seqslab-cli-3.2.6/python/seqslab/trs/resource → seqslab-cli-3.2.7/python/seqslab/trs/internal}/__init__.py +0 -0
  74. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/internal/utils.py +0 -0
  75. {seqslab-cli-3.2.6/python/seqslab/trs/template → seqslab-cli-3.2.7/python/seqslab/trs/register}/__init__.py +0 -0
  76. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/register/azure.py +0 -0
  77. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/register/base.py +0 -0
  78. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/register/common.py +0 -0
  79. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/register/template.py +0 -0
  80. {seqslab-cli-3.2.6/python/seqslab/user/internal → seqslab-cli-3.2.7/python/seqslab/trs/resource}/__init__.py +0 -0
  81. {seqslab-cli-3.2.6/python/seqslab/user/resource → seqslab-cli-3.2.7/python/seqslab/trs/template}/__init__.py +0 -0
  82. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/trs/template/template.py +0 -0
  83. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/usage_logger.py +0 -0
  84. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/user/__init__.py +0 -0
  85. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/user/commands.py +0 -0
  86. {seqslab-cli-3.2.6/python/seqslab/wes → seqslab-cli-3.2.7/python/seqslab/user}/internal/__init__.py +0 -0
  87. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/user/internal/common.py +0 -0
  88. {seqslab-cli-3.2.6/python/seqslab/wes → seqslab-cli-3.2.7/python/seqslab/user}/resource/__init__.py +0 -0
  89. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/user/resource/azure.py +0 -0
  90. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/user/resource/base.py +0 -0
  91. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/__init__.py +0 -0
  92. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/commands.py +0 -0
  93. {seqslab-cli-3.2.6/python/seqslab/wes/template → seqslab-cli-3.2.7/python/seqslab/wes/internal}/__init__.py +0 -0
  94. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/internal/common.py +0 -0
  95. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/internal/parameters.py +0 -0
  96. {seqslab-cli-3.2.6/python/seqslab/workspace/internal → seqslab-cli-3.2.7/python/seqslab/wes/resource}/__init__.py +0 -0
  97. {seqslab-cli-3.2.6/python/seqslab/trs → seqslab-cli-3.2.7/python/seqslab/wes}/resource/azure.py +0 -0
  98. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/resource/base.py +0 -0
  99. {seqslab-cli-3.2.6/python/seqslab/workspace/resource → seqslab-cli-3.2.7/python/seqslab/wes/template}/__init__.py +0 -0
  100. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/template/base.py +0 -0
  101. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/wes/template/template.py +0 -0
  102. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/workspace/__init__.py +0 -0
  103. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab/workspace/internal/common.py +0 -0
  104. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab_cli.egg-info/dependency_links.txt +0 -0
  105. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab_cli.egg-info/entry_points.txt +0 -0
  106. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab_cli.egg-info/top_level.txt +0 -0
  107. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/python/seqslab_cli.egg-info/zip-safe +0 -0
  108. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/setup.cfg +0 -0
  109. {seqslab-cli-3.2.6 → seqslab-cli-3.2.7}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: seqslab-cli
3
- Version: 3.2.6
3
+ Version: 3.2.7
4
4
  Summary: Atgenomix SeqsLab Command Line Tool
5
5
  Home-page: https://github.com/AnomeGAP/seqslab-cli
6
6
  Author: Allen Chang
@@ -23,7 +23,7 @@ __all__ = [
23
23
  ]
24
24
 
25
25
 
26
- __version__ = "3.2.6"
26
+ __version__ = "3.2.7"
27
27
 
28
28
  LOGGING = {
29
29
  "DIR_PATH": "/var/log/seqslab"
@@ -21,7 +21,7 @@ import signal
21
21
 
22
22
  from nubia import Nubia, Options
23
23
 
24
- from seqslab import auth, drs, wes, trs, workspace, user, role, organization
24
+ from seqslab import auth, drs, wes, trs, workspace, user, role, organization, scr
25
25
  from seqslab.plugin import SQLBPlugin
26
26
 
27
27
 
@@ -42,7 +42,7 @@ def main():
42
42
  plugin = SQLBPlugin()
43
43
  shell = Nubia(
44
44
  name="seqslab-cli",
45
- command_pkgs=[auth, drs, wes, trs, workspace, user, role, organization],
45
+ command_pkgs=[auth, drs, wes, trs, workspace, user, role, organization, scr],
46
46
  plugin=plugin,
47
47
  options=Options(
48
48
  persistent_history=False,
@@ -63,6 +63,7 @@ class DRSregister:
63
63
  DRS_RESOURCES_URL = f"https://{API_HOSTNAME}/ga4gh/drs/{__version__}/service-info/workspaces/{{" \
64
64
  f"name}}/resources/?backend={{backend}} "
65
65
  DRS_UPLOAD_URL = f"https://{API_HOSTNAME}/ga4gh/drs/{__version__}/objects/upload/?backend={{backend}}"
66
+ DRS_CONTENTS_ACCESS_URL = f"https://{API_HOSTNAME}/ga4gh/drs/{__version__}/contents/{{object_id}}/access/"
66
67
 
67
68
  @lru_cache(maxsize=16)
68
69
  def root_path(self, workspace_name: str) -> str:
@@ -346,3 +347,19 @@ class DRSregister:
346
347
  checksums=obj.get('checksums')
347
348
  )._asdict()
348
349
  return results
350
+
351
+ def create_download_link(self, drs_id: str):
352
+ """
353
+ api: ga4gh/drs/v1/contents/${drs_id}/access/
354
+ :response: download url for the given drs_id
355
+ """
356
+ try:
357
+ token = BaseAuth.get_token().get("tokens").get("access")
358
+ except KeyError:
359
+ raise KeyError(f"No tokens, Please sign in first!")
360
+
361
+ with requests.post(url=self.DRS_CONTENTS_ACCESS_URL.format(object_id=drs_id),
362
+ headers={"Authorization": f"Bearer {token}"}) as response:
363
+ if response.status_code not in [requests.codes.created]:
364
+ raise requests.HTTPError(f"{response.status_code}: {repr(response.text)}")
365
+ return response.json()
@@ -347,6 +347,34 @@ class BaseDatahub:
347
347
  __log(result, output)
348
348
  return 0
349
349
 
350
+ @command
351
+ @argument("workspace",
352
+ type=str,
353
+ positional=False,
354
+ description="Specify the workspace based on the signed in account (required).", )
355
+ @argument("id",
356
+ type=str,
357
+ positional=False,
358
+ description="A DRS object ID (required if there is no self URI).")
359
+ def share_link(self, workspace: str, id: str) -> int:
360
+ """
361
+ Generate a share link enabling external users to download the DRS object as a zip archive through web
362
+ browsers. The share link expires either after the first successful download or after a period of three months.
363
+ """
364
+
365
+ if not workspace:
366
+ logging.error("Invalid workspace name")
367
+ cprint("Invalid workspace name", "red")
368
+ return errno.EINVAL
369
+
370
+ api_backend = drs_register().load_register(workspace)
371
+ r = api_backend.create_download_link(drs_id=id)
372
+
373
+ if isinstance(r, int):
374
+ return r
375
+ cprint(r.get('url'), 'yellow')
376
+ return 0
377
+
350
378
  @staticmethod
351
379
  @async_exception_handler
352
380
  async def _download(drs_id: str, dst: str, **kwargs):
@@ -0,0 +1,15 @@
1
+ import environ
2
+
3
+ env = environ.Env()
4
+ environ.Env.read_env("/etc/seqslab/cli_apps.env")
5
+
6
+ name = "scr"
7
+
8
+ __all__ = [
9
+
10
+ ]
11
+
12
+ __version__ = "v3"
13
+
14
+ PRIVATE_NAME = env.str("PRIVATE_NAME", "api")
15
+ API_HOSTNAME = f"{PRIVATE_NAME}.seqslab.net"
@@ -0,0 +1,209 @@
1
+ import base64
2
+ import csv
3
+ import errno
4
+ import json
5
+ import logging
6
+ import re
7
+ from io import StringIO
8
+ from typing import List
9
+
10
+ from nubia import argument, command, context
11
+ from tabulate import tabulate
12
+ from termcolor import cprint
13
+
14
+ from seqslab.exceptions import exception_handler
15
+ from .internal.common import get_factory
16
+
17
+
18
+ class BaseSCR:
19
+
20
+ @command(aliases=[])
21
+ @argument("reload",
22
+ type=bool,
23
+ positional=False,
24
+ description="Specify whether to force reload system cache for SCR (optional, default = False).")
25
+ def list(self, reload: bool = False) -> int:
26
+ """
27
+ List all SCR records.
28
+ """
29
+
30
+ backend = get_factory().load_resource()
31
+ result = backend.list_scr(reload)
32
+
33
+ if isinstance(result, int):
34
+ return result
35
+ self.__log(result)
36
+ return 0
37
+
38
+ @command(aliases=[])
39
+ @argument("login_server",
40
+ type=str,
41
+ positional=False,
42
+ description="Specify a container registry login endpoint, e.g. docker.io (required).")
43
+ @argument("username",
44
+ type=str,
45
+ positional=False,
46
+ description="Specify the account for this container registry (required).")
47
+ @argument("password",
48
+ type=str,
49
+ positional=False,
50
+ description="Specify the password for this container registry (required).")
51
+ def register(self, login_server: str, username: str, password: str) -> int:
52
+ """
53
+ Register a container registry to SCR.
54
+ """
55
+
56
+ backend = get_factory().load_resource()
57
+ kwargs = {"login_server": login_server, "username": username, "password": password}
58
+ result = backend.register_scr(**kwargs)
59
+
60
+ if isinstance(result, int):
61
+ return result
62
+ self.__log(result)
63
+ return 0
64
+
65
+ @command(aliases=[])
66
+ @argument("id",
67
+ type=str,
68
+ positional=False,
69
+ description="Specify the ID of the SCR (required).")
70
+ @argument("reload",
71
+ type=bool,
72
+ positional=False,
73
+ description="Specify whether to force reload system cache for SCR (optional, default = False).")
74
+ def get(self, id: str, reload: bool = False) -> int:
75
+ """
76
+ Get an SCR record.
77
+ """
78
+
79
+ backend = get_factory().load_resource()
80
+ kwargs = {"id": id, "reload": reload}
81
+ result = backend.get_scr(**kwargs)
82
+ if isinstance(result, int):
83
+ return result
84
+
85
+ auth = base64.b64decode(result.get('authorization')[6:]).decode('utf-8').split(':')
86
+ result['username'] = auth[0]
87
+ result['password'] = auth[1]
88
+
89
+ self.__log(result)
90
+ return 0
91
+
92
+ @command(aliases=[])
93
+ @argument("id",
94
+ type=str,
95
+ positional=False,
96
+ description="Specify the ID of an SCR (required).")
97
+ @argument("username",
98
+ type=str,
99
+ positional=False,
100
+ description="Specify the account for this container registry (optional).")
101
+ @argument("password",
102
+ type=str,
103
+ positional=False,
104
+ description="Specify the password for this container registry (optional).")
105
+ def update(self, id: str, username: str = '', password: str = '') -> int:
106
+ """
107
+ Update an SCR record.
108
+ """
109
+
110
+ backend = get_factory().load_resource()
111
+ kwargs = {}
112
+ if username:
113
+ kwargs['username'] = username
114
+ if password:
115
+ kwargs["password"] = password
116
+ if not kwargs:
117
+ cprint('Nothing to be done due to username and password are not given')
118
+ return 0
119
+
120
+ result = backend.update_scr(id, **kwargs)
121
+ if isinstance(result, int):
122
+ return result
123
+ self.__log(result)
124
+ return 0
125
+
126
+ @command(aliases=[])
127
+ @argument("id",
128
+ type=str,
129
+ positional=False,
130
+ description="Specify the ID of the SCR (required).")
131
+ def deregister(self, id: str) -> int:
132
+ """
133
+ Deregister an SCR record.
134
+ """
135
+
136
+ backend = get_factory().load_resource()
137
+ kwargs = {}
138
+ result = backend.deregister_scr(id, **kwargs)
139
+
140
+ if isinstance(result, int):
141
+ return result
142
+ self.__log(result)
143
+ return 0
144
+
145
+ @command(aliases=[])
146
+ @argument("id",
147
+ type=str,
148
+ positional=False,
149
+ description="Specify the ID of the SCR (required).")
150
+ @argument("repository",
151
+ type=str,
152
+ positional=False,
153
+ description="Specify the repository name (required).")
154
+ @argument("reload",
155
+ type=bool,
156
+ positional=False,
157
+ description="Specify whether to force reload system cache for SCR (optional, default = False).")
158
+ def repository(self, id: str, repository: str, reload: bool = False) -> int:
159
+ """
160
+ Get repository.
161
+ """
162
+
163
+ backend = get_factory().load_resource()
164
+ kwargs = {"registry_id": id, "repository_name": repository, "reload": reload}
165
+ result = backend.get_repository(**kwargs)
166
+ if isinstance(result, int):
167
+ return result
168
+
169
+ self.__log(result)
170
+ return 0
171
+
172
+ def __log(self, results):
173
+ self._stdout(results=results, output='json')
174
+ msg = f"List all workspaces."
175
+ logging.info(msg)
176
+
177
+ @staticmethod
178
+ def _stdout(results: List[dict], output: str) -> int:
179
+ """
180
+ stdout:: support different format [json, tsv, table]
181
+ """
182
+ if output == "tsv":
183
+ s = StringIO()
184
+ writer = csv.DictWriter(s, fieldnames=list(results[0].keys()))
185
+ writer.writeheader()
186
+ for result in results:
187
+ writer.writerow(result)
188
+ s.seek(0)
189
+ content = s.read().replace(',', '\t')
190
+ cprint(content)
191
+ elif output == 'table':
192
+ table_header = list(results[0].keys())
193
+ table_datas = [result.values() for result in results]
194
+ cprint(tabulate(
195
+ tabular_data=table_datas,
196
+ headers=table_header,
197
+ tablefmt='pipe'
198
+ ))
199
+ else:
200
+ cprint(json.dumps(results, indent=4))
201
+ return 0
202
+
203
+
204
+ @command
205
+ class scr(BaseSCR):
206
+ """ SeqsLab Container Registry SCR commands"""
207
+
208
+ def __init__(self):
209
+ pass
@@ -0,0 +1,46 @@
1
+ import sys
2
+ from typing import TypeVar
3
+
4
+ from nubia import context
5
+ from seqslab.wes.resource.azure import AzureResource
6
+ from seqslab.settings import SCR_RESOURCE_BACKEND
7
+
8
+
9
+ """
10
+ Copyright (C) 2022, Atgenomix Incorporated.
11
+
12
+ All Rights Reserved.
13
+
14
+ This program is an unpublished copyrighted work which is proprietary to
15
+ Atgenomix Incorporated and contains confidential information that is not to
16
+ be reproduced or disclosed to any other person or entity without prior
17
+ written consent from Atgenomix, Inc. in each and every instance.
18
+
19
+ Unauthorized reproduction of this program as well as unauthorized
20
+ preparation of derivative works based upon the program or distribution of
21
+ copies by sale, rental, lease or lending are violations of federal copyright
22
+ laws and state trade secret laws, punishable by civil and criminal penalties.
23
+ """
24
+
25
+ Resource = TypeVar("Resource", bound=AzureResource)
26
+
27
+
28
+ class Factory:
29
+ """Storage backend factory"""
30
+
31
+ @staticmethod
32
+ def load_resource() -> Resource:
33
+ backend = context.get_context().args.backend
34
+ name = SCR_RESOURCE_BACKEND.get(backend)
35
+ mod, mem = name.rsplit(".", 1)
36
+ __import__(mod)
37
+ module = sys.modules[mod]
38
+ backend_class = getattr(module, mem)
39
+ return backend_class()
40
+
41
+
42
+ _factory = Factory()
43
+
44
+
45
+ def get_factory():
46
+ return _factory
@@ -0,0 +1,124 @@
1
+ import requests
2
+ import logging
3
+ from tenacity import retry, wait_fixed, stop_after_attempt
4
+ from seqslab.auth.commands import BaseAuth
5
+ from seqslab import trs, drs, wes, workspace, scr
6
+ from functools import lru_cache
7
+ from nubia import context
8
+
9
+
10
+ class BaseResource:
11
+ logger = logging.getLogger()
12
+ TRS_BASE_URL = f"https://{trs.API_HOSTNAME}/trs/{trs.__version__}"
13
+ TRS_CR_URL = f"{TRS_BASE_URL}/container-registry/"
14
+ TRS_CR_REPO_URL = f"{TRS_CR_URL}{{registry_id}}/repository/{{repository_name}}"
15
+ @staticmethod
16
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
17
+ def request_wrapper(
18
+ callback,
19
+ url,
20
+ headers,
21
+ status,
22
+ data=None,
23
+ stream=False,
24
+ ) -> requests.Response:
25
+ with callback(url, headers=headers, data=data, stream=stream) as r:
26
+ if r.status_code in status:
27
+ return r
28
+ r.raise_for_status()
29
+
30
+ @staticmethod
31
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
32
+ @lru_cache(maxsize=16)
33
+ def list_scr(reload: bool):
34
+ ctx = context.get_context()
35
+ backend = ctx.args.backend
36
+ token = BaseAuth.get_token().get("tokens").get("access")
37
+ url = BaseResource.TRS_CR_URL.format(backend=backend) + f'?backend={backend}'
38
+ if reload:
39
+ url += f'&force=true'
40
+ r = BaseResource.request_wrapper(
41
+ callback=requests.get,
42
+ url=BaseResource.TRS_CR_URL.format(backend=backend),
43
+ headers={"Authorization": f"Bearer {token}"},
44
+ status=[requests.codes.ok])
45
+ return r.json()
46
+
47
+ @staticmethod
48
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
49
+ def register_scr(**kwargs):
50
+ ctx = context.get_context()
51
+ backend = ctx.args.backend
52
+ token = BaseAuth.get_token().get("tokens").get("access")
53
+ r = BaseResource.request_wrapper(
54
+ callback=requests.post,
55
+ url=BaseResource.TRS_CR_URL.format(backend=backend) + f'?backend={backend}',
56
+ headers={"Authorization": f"Bearer {token}"},
57
+ status=[requests.codes.created],
58
+ data=kwargs)
59
+ return r.json()
60
+
61
+ @staticmethod
62
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
63
+ @lru_cache(maxsize=16)
64
+ def get_scr(**kwargs):
65
+ ctx = context.get_context()
66
+ backend = ctx.args.backend
67
+ token = BaseAuth.get_token().get("tokens").get("access")
68
+ url = BaseResource.TRS_CR_URL.format(backend=backend) + f"{kwargs.get('id')}/"
69
+ if kwargs.get('reload'):
70
+ url += '?force=true'
71
+
72
+ r = BaseResource.request_wrapper(
73
+ callback=requests.get,
74
+ url=url,
75
+ headers={"Authorization": f"Bearer {token}"},
76
+ status=[requests.codes.ok])
77
+ return r.json()
78
+
79
+ @staticmethod
80
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
81
+ def update_scr(scr_id: str, **kwargs):
82
+ ctx = context.get_context()
83
+ backend = ctx.args.backend
84
+ token = BaseAuth.get_token().get("tokens").get("access")
85
+ r = BaseResource.request_wrapper(
86
+ callback=requests.patch,
87
+ url=BaseResource.TRS_CR_URL.format(backend=backend) + f'{scr_id}/',
88
+ headers={"Authorization": f"Bearer {token}"},
89
+ data=kwargs,
90
+ status=[requests.codes.ok])
91
+ return r.json()
92
+
93
+ @staticmethod
94
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
95
+ def deregister_scr(scr_id: str, **kwargs):
96
+ ctx = context.get_context()
97
+ backend = ctx.args.backend
98
+ token = BaseAuth.get_token().get("tokens").get("access")
99
+ BaseResource.request_wrapper(
100
+ callback=requests.delete,
101
+ url=BaseResource.TRS_CR_URL.format(backend=backend) + f'{scr_id}/',
102
+ headers={"Authorization": f"Bearer {token}"},
103
+ status=[requests.codes.no_content])
104
+
105
+ @staticmethod
106
+ @retry(stop=stop_after_attempt(3), wait=wait_fixed(2), reraise=True)
107
+ @lru_cache(maxsize=16)
108
+ def get_repository(**kwargs):
109
+ ctx = context.get_context()
110
+ backend = ctx.args.backend
111
+ token = BaseAuth.get_token().get("tokens").get("access")
112
+ url = BaseResource.TRS_CR_REPO_URL.format(
113
+ registry_id=kwargs.get('registry_id'),
114
+ repository_name=kwargs.get('repository_name'),
115
+ )
116
+ if kwargs.get('reload'):
117
+ url += '?force=true'
118
+
119
+ r = BaseResource.request_wrapper(
120
+ callback=requests.get,
121
+ url=url,
122
+ headers={"Authorization": f"Bearer {token}"},
123
+ status=[requests.codes.ok])
124
+ return r.json()
@@ -33,4 +33,8 @@ ROLE_RESOURCE_BACKEND = {
33
33
 
34
34
  USER_RESOURCE_BACKEND = {
35
35
  "azure": "seqslab.user.resource.azure.AzureResource",
36
+ }
37
+
38
+ SCR_RESOURCE_BACKEND = {
39
+ "azure": "seqslab.scr.resource.azure.AzureResource",
36
40
  }
@@ -271,21 +271,31 @@ class BaseTools:
271
271
  return 0
272
272
 
273
273
  @command
274
- @argument("workspace",
274
+ @argument("scr_id",
275
275
  type=str,
276
- description="Specify the workspace based on the signed in account (required).")
277
- def images(self, workspace) -> int:
276
+ description="Specify SCR ID (required).")
277
+ @argument("repositories",
278
+ type=List[str],
279
+ positional=False,
280
+ description="Specify the repository names you want to query (required).")
281
+ @argument("reload",
282
+ type=bool,
283
+ positional=False,
284
+ description="Specify whether to force reload system cache for SCR (optional, default = False).")
285
+ def images(self, scr_id: str, repositories: List[str] = [], reload: bool = False) -> int:
278
286
  """
279
- List Docker images in the workspace.container_registry.
287
+ List image tags and details of given repositories in an SCR.
280
288
  """
281
- if not workspace:
282
- cprint("Enter a valid workspace", "red")
289
+ if not repositories:
290
+ cprint("Enter at least one repository", "red")
283
291
  return errno.EIO
284
292
  try:
285
- resource = trs_resource().load_resource(workspace)
286
- ret = resource.container_registry(workspace)
293
+ resource = trs_resource().load_resource()
294
+ ret = resource.container_registry(scr_id, repositories, reload)
287
295
  images_info = TrsImagesTemplate().create(ret)
288
- cprint(f'workspace {workspace} image list:\n----------------------------------------------', 'yellow')
296
+ cprint(f'SCR ID: {scr_id}\n'
297
+ f'Repository list: {repositories}\n'
298
+ f'image list:\n----------------------------------------------', 'yellow')
289
299
  for img in images_info:
290
300
  cprint(json.dumps(img), 'yellow')
291
301
  return 0
@@ -21,5 +21,5 @@ class AzureResource(BaseResource):
21
21
  Azure Compute services provides computation resource in Azure cloud.
22
22
  """
23
23
 
24
- def __init__(self, workspace):
25
- super().__init__(workspace)
24
+ def __init__(self):
25
+ super().__init__()
@@ -4,7 +4,7 @@ from abc import ABC
4
4
  from functools import lru_cache
5
5
  from types import TracebackType
6
6
  from typing import (
7
- Union, Any, Optional, NoReturn, Type, NamedTuple, OrderedDict
7
+ Union, Any, Optional, NoReturn, Type, NamedTuple, OrderedDict, List
8
8
  )
9
9
 
10
10
  import aiohttp
@@ -40,11 +40,7 @@ class BaseResource(ABC):
40
40
  logger = logging.getLogger()
41
41
 
42
42
  TOKENS_KEY = "tokens"
43
- TRS_WORKSPACE_URL = f"https://{API_HOSTNAME}/trs/{__version__}/service-info/workspaces/?backend={{backend}}"
44
- TRS_RESOURCES_URL = f"https://{API_HOSTNAME}/trs/{__version__}/service-info/workspaces/{{" \
45
- f"name}}/resources/?backend={{backend}}"
46
- TRS_CONTAINER_REGISTRY_URL = f"https://{API_HOSTNAME}/trs/{__version__}/service-info/workspaces/{{" \
47
- f"name}}/container-registries/?backend={{backend}}"
43
+ TRS_CONTAINER_REGISTRY_URL = f"https://{API_HOSTNAME}/trs/{__version__}/container-registry/{{scr_id}}"
48
44
 
49
45
  class Response(NamedTuple):
50
46
  status: int
@@ -52,11 +48,7 @@ class BaseResource(ABC):
52
48
  body: Any = None
53
49
  attrs: OrderedDict = {}
54
50
 
55
- def __init__(self, workspace):
56
- """
57
- :param workspace: resource group in Azure, or project in GCS
58
- """
59
- self._workspace = workspace
51
+ def __init__(self):
60
52
  self.session = aiohttp.ClientSession(raise_for_status=True)
61
53
 
62
54
  def __enter__(self) -> "BaseResource":
@@ -98,26 +90,15 @@ class BaseResource(ABC):
98
90
 
99
91
  @staticmethod
100
92
  @retry(stop=stop_after_attempt(3), wait=wait_fixed(5), reraise=True)
101
- @lru_cache(maxsize=16)
102
- def workspace(name) -> dict:
103
- ctx = context.get_context()
104
- backend = ctx.args.backend
105
- token = BaseAuth.get_token().get("tokens").get("access")
106
- url = BaseResource.TRS_RESOURCES_URL.format(name=name, backend=backend)
107
- with requests.get(url,
108
- headers={"Authorization": f"Bearer {token}"}) as response:
109
- if response.status_code not in [requests.codes.ok]:
110
- raise requests.HTTPError()
111
- return response.json()
112
-
113
- @staticmethod
114
- @retry(stop=stop_after_attempt(3), wait=wait_fixed(5), reraise=True)
115
- @lru_cache(maxsize=16)
116
- def container_registry(name) -> dict:
93
+ def container_registry(scr_id: str, repositories: List[str], reload: bool) -> dict:
117
94
  ctx = context.get_context()
118
95
  backend = ctx.args.backend
119
96
  token = BaseAuth.get_token().get("tokens").get("access")
120
- with requests.get(BaseResource.TRS_CONTAINER_REGISTRY_URL.format(name=name, backend=backend),
97
+ qp = f'?force={reload}'
98
+ for repo in repositories:
99
+ qp += f'&repositories={repo}'
100
+ print(BaseResource.TRS_CONTAINER_REGISTRY_URL.format(scr_id=scr_id) + f'{qp}')
101
+ with requests.get(BaseResource.TRS_CONTAINER_REGISTRY_URL.format(scr_id=scr_id) + f'{qp}',
121
102
  headers={"Authorization": f"Bearer {token}"}) as response:
122
103
  if response.status_code not in [requests.codes.ok]:
123
104
  raise requests.HTTPError('{"detail":"Workspace must be in SeqsLab supported Azure resource group.",'
@@ -29,14 +29,14 @@ class Factory:
29
29
  """Storage backend factory"""
30
30
 
31
31
  @staticmethod
32
- def load_resource(workspace: str) -> Resource:
32
+ def load_resource() -> Resource:
33
33
  backend = context.get_context().args.backend
34
34
  name = TRS_RESOURCE_BACKEND.get(backend)
35
35
  mod, mem = name.rsplit(".", 1)
36
36
  __import__(mod)
37
37
  module = sys.modules[mod]
38
38
  backend_class = getattr(module, mem)
39
- return backend_class(workspace)
39
+ return backend_class()
40
40
 
41
41
 
42
42
  _factory = Factory()
@@ -180,10 +180,10 @@ class TrsImagesTemplate:
180
180
  @staticmethod
181
181
  def create(container_registry_info: dict) -> dict:
182
182
  image_list = []
183
- cr = container_registry_info.get('login_server')
183
+ cr = container_registry_info.get('login_server', None)
184
184
  for repo in container_registry_info.get('repositories', []):
185
185
  name = repo.get('name')
186
- for tag in repo.get('tags'):
186
+ for tag in repo.get('tags', []):
187
187
  pass
188
188
  image_list.append({
189
189
  "image_type": tag.get('type'),