chris.client.admin
1import io 2import json 3from typing import Iterable 4 5import aiohttp 6from async_property import async_cached_property 7from serde import from_dict 8 9from chris.client.authed import AuthenticatedClient 10from chris.link import http 11from chris.link.collection_client import CollectionJsonApiClient 12from chris.link.linked import deserialize_linked 13from chris.models.collection_links import AdminCollectionLinks, AdminApiCollectionLinks 14from chris.models.logged_in import Plugin 15from chris.models.public import ComputeResource 16from chris.models.types import PluginUrl, ComputeResourceName, PfconUrl 17from chris.util.errors import raise_for_status 18 19 20class _AdminApiClient(CollectionJsonApiClient[AdminApiCollectionLinks]): 21 """ 22 A client to `/chris-admin/api/v1/` 23 """ 24 25 @http.post("compute_resources") 26 async def create_compute_resource(self, **kwargs) -> ComputeResource: 27 ... 28 29 30class ChrisAdminClient(AuthenticatedClient[AdminCollectionLinks, "ChrisAdminClient"]): 31 """ 32 A client who has access to `/chris-admin/`. Admins can register new plugins and 33 add new compute resources. 34 """ 35 36 @http.post("admin") 37 async def _register_plugin_from_store_raw( 38 self, plugin_store_url: str, compute_names: str 39 ) -> Plugin: 40 ... 41 42 async def register_plugin_from_store( 43 self, plugin_store_url: PluginUrl, compute_names: Iterable[ComputeResourceName] 44 ) -> Plugin: 45 """ 46 Register a plugin from a ChRIS Store. 47 """ 48 return await self._register_plugin_from_store_raw( 49 plugin_store_url=plugin_store_url, compute_names=",".join(compute_names) 50 ) 51 52 async def add_plugin( 53 self, 54 plugin_description: str | dict, 55 compute_resources: str 56 | ComputeResource 57 | Iterable[ComputeResource | ComputeResourceName], 58 fname: str = "Plugin.json", 59 ) -> Plugin: 60 """ 61 Add a plugin to *CUBE*. 62 63 Examples 64 -------- 65 66 ```python 67 cmd = ['docker', 'run', '--rm', 'fnndsc/pl-mri-preview', 'chris_plugin_info'] 68 output = subprocess.check_output(cmd, text=True) 69 desc = json.loads(output) 70 desc['name'] = 'pl-mri-preview' 71 desc['public_repo'] = 'https://github.com/FNNDSC/pl-mri-preview' 72 desc['dock_image'] = 'fnndsc/pl-mri-preview' 73 74 await chris_admin.add_plugin(plugin_description=desc, compute_resources='host') 75 ``` 76 77 The example above is just for show. It's not a good example for several reasons: 78 79 - Calls blocking function `subprocess.check_output` in asynchronous context 80 - It is preferred to use a versioned string for `dock_image` 81 - `host` compute environment is not guaranteed to exist. Instead, you could 82 call `chris.client.authed.AuthenticatedClient.search_compute_resources` 83 or `chris.client.authed.AuthenticatedClient.get_all_compute_resources`: 84 85 ```python 86 all_computes = await chris_admin.get_all_compute_resources() 87 await chris_admin.add_plugin(plugin_description=desc, compute_resources=all_computes) 88 ``` 89 90 Parameters 91 ---------- 92 plugin_description: str | dict 93 JSON description of a plugin. 94 [spec](https://github.com/FNNDSC/CHRIS_docs/blob/5078aaf934bdbe313e85367f88aff7c14730a1d4/specs/ChRIS_Plugins.adoc#descriptor_file) 95 compute_resources 96 Compute resources to register the plugin to. Value can be either a comma-separated `str` of names, 97 a `chris.models.public.ComputeResource`, a sequence of `chris.models.public.ComputeResource`, 98 or a sequence of compute resource names as `str`. 99 fname: str 100 File name to send along in the multi-part POST request. Not important. 101 """ 102 compute_names = _serialize_crs(compute_resources) 103 if not isinstance(plugin_description, str): 104 plugin_description = json.dumps(plugin_description) 105 data = aiohttp.FormData() 106 data.add_field("fname", io.StringIO(plugin_description), filename=fname) 107 data.add_field("compute_names", compute_names) 108 async with self.s.post(self.collection_links.admin, data=data) as res: 109 await raise_for_status(res) 110 return deserialize_linked(self, Plugin, await res.json()) 111 112 async def create_compute_resource( 113 self, 114 name: str | ComputeResourceName, 115 compute_url: str | PfconUrl, 116 compute_user: str, 117 compute_password: str, 118 description: str = None, 119 compute_auth_url: str = None, 120 compute_auth_token: str = None, 121 max_job_exec_seconds: str = None, 122 ) -> ComputeResource: 123 """ 124 Define a new compute resource. 125 """ 126 return await (await self._admin).create_compute_resource( 127 name=name, 128 compute_url=compute_url, 129 compute_user=compute_user, 130 compute_password=compute_password, 131 description=description, 132 compute_auth_url=compute_auth_url, 133 compute_auth_token=compute_auth_token, 134 max_job_exec_seconds=max_job_exec_seconds, 135 ) 136 137 @async_cached_property 138 async def _admin(self) -> _AdminApiClient: 139 """ 140 Get a (sub-)client for `/chris-admin/api/v1/` 141 """ 142 res = await self.s.get(self.collection_links.admin) 143 body = await res.json() 144 links = from_dict(AdminApiCollectionLinks, body["collection_links"]) 145 return _AdminApiClient( 146 url=self.collection_links.admin, 147 s=self.s, 148 collection_links=links, 149 max_search_requests=self.max_search_requests, 150 ) 151 152 153def _serialize_crs( 154 c: str | ComputeResource | Iterable[ComputeResource | ComputeResourceName], 155) -> str: 156 if isinstance(c, str): 157 return c 158 if isinstance(c, ComputeResource): 159 return c.name 160 if not isinstance(c, Iterable): 161 raise TypeError("compute_resources must be str or Iterable") 162 return ",".join(map(_serialize_cr, c)) 163 164 165def _serialize_cr(c: str | ComputeResource): 166 if isinstance(c, ComputeResource): 167 return c.name 168 return str(c)
class
ChrisAdminClient(chris.client.authed.AuthenticatedClient[chris.models.collection_links.AdminCollectionLinks, 'ChrisAdminClient']):
31class ChrisAdminClient(AuthenticatedClient[AdminCollectionLinks, "ChrisAdminClient"]): 32 """ 33 A client who has access to `/chris-admin/`. Admins can register new plugins and 34 add new compute resources. 35 """ 36 37 @http.post("admin") 38 async def _register_plugin_from_store_raw( 39 self, plugin_store_url: str, compute_names: str 40 ) -> Plugin: 41 ... 42 43 async def register_plugin_from_store( 44 self, plugin_store_url: PluginUrl, compute_names: Iterable[ComputeResourceName] 45 ) -> Plugin: 46 """ 47 Register a plugin from a ChRIS Store. 48 """ 49 return await self._register_plugin_from_store_raw( 50 plugin_store_url=plugin_store_url, compute_names=",".join(compute_names) 51 ) 52 53 async def add_plugin( 54 self, 55 plugin_description: str | dict, 56 compute_resources: str 57 | ComputeResource 58 | Iterable[ComputeResource | ComputeResourceName], 59 fname: str = "Plugin.json", 60 ) -> Plugin: 61 """ 62 Add a plugin to *CUBE*. 63 64 Examples 65 -------- 66 67 ```python 68 cmd = ['docker', 'run', '--rm', 'fnndsc/pl-mri-preview', 'chris_plugin_info'] 69 output = subprocess.check_output(cmd, text=True) 70 desc = json.loads(output) 71 desc['name'] = 'pl-mri-preview' 72 desc['public_repo'] = 'https://github.com/FNNDSC/pl-mri-preview' 73 desc['dock_image'] = 'fnndsc/pl-mri-preview' 74 75 await chris_admin.add_plugin(plugin_description=desc, compute_resources='host') 76 ``` 77 78 The example above is just for show. It's not a good example for several reasons: 79 80 - Calls blocking function `subprocess.check_output` in asynchronous context 81 - It is preferred to use a versioned string for `dock_image` 82 - `host` compute environment is not guaranteed to exist. Instead, you could 83 call `chris.client.authed.AuthenticatedClient.search_compute_resources` 84 or `chris.client.authed.AuthenticatedClient.get_all_compute_resources`: 85 86 ```python 87 all_computes = await chris_admin.get_all_compute_resources() 88 await chris_admin.add_plugin(plugin_description=desc, compute_resources=all_computes) 89 ``` 90 91 Parameters 92 ---------- 93 plugin_description: str | dict 94 JSON description of a plugin. 95 [spec](https://github.com/FNNDSC/CHRIS_docs/blob/5078aaf934bdbe313e85367f88aff7c14730a1d4/specs/ChRIS_Plugins.adoc#descriptor_file) 96 compute_resources 97 Compute resources to register the plugin to. Value can be either a comma-separated `str` of names, 98 a `chris.models.public.ComputeResource`, a sequence of `chris.models.public.ComputeResource`, 99 or a sequence of compute resource names as `str`. 100 fname: str 101 File name to send along in the multi-part POST request. Not important. 102 """ 103 compute_names = _serialize_crs(compute_resources) 104 if not isinstance(plugin_description, str): 105 plugin_description = json.dumps(plugin_description) 106 data = aiohttp.FormData() 107 data.add_field("fname", io.StringIO(plugin_description), filename=fname) 108 data.add_field("compute_names", compute_names) 109 async with self.s.post(self.collection_links.admin, data=data) as res: 110 await raise_for_status(res) 111 return deserialize_linked(self, Plugin, await res.json()) 112 113 async def create_compute_resource( 114 self, 115 name: str | ComputeResourceName, 116 compute_url: str | PfconUrl, 117 compute_user: str, 118 compute_password: str, 119 description: str = None, 120 compute_auth_url: str = None, 121 compute_auth_token: str = None, 122 max_job_exec_seconds: str = None, 123 ) -> ComputeResource: 124 """ 125 Define a new compute resource. 126 """ 127 return await (await self._admin).create_compute_resource( 128 name=name, 129 compute_url=compute_url, 130 compute_user=compute_user, 131 compute_password=compute_password, 132 description=description, 133 compute_auth_url=compute_auth_url, 134 compute_auth_token=compute_auth_token, 135 max_job_exec_seconds=max_job_exec_seconds, 136 ) 137 138 @async_cached_property 139 async def _admin(self) -> _AdminApiClient: 140 """ 141 Get a (sub-)client for `/chris-admin/api/v1/` 142 """ 143 res = await self.s.get(self.collection_links.admin) 144 body = await res.json() 145 links = from_dict(AdminApiCollectionLinks, body["collection_links"]) 146 return _AdminApiClient( 147 url=self.collection_links.admin, 148 s=self.s, 149 collection_links=links, 150 max_search_requests=self.max_search_requests, 151 )
A client who has access to /chris-admin/
. Admins can register new plugins and
add new compute resources.
async def
register_plugin_from_store( self, plugin_store_url: chris.models.types.PluginUrl, compute_names: Iterable[chris.models.types.ComputeResourceName]) -> chris.models.logged_in.Plugin:
43 async def register_plugin_from_store( 44 self, plugin_store_url: PluginUrl, compute_names: Iterable[ComputeResourceName] 45 ) -> Plugin: 46 """ 47 Register a plugin from a ChRIS Store. 48 """ 49 return await self._register_plugin_from_store_raw( 50 plugin_store_url=plugin_store_url, compute_names=",".join(compute_names) 51 )
Register a plugin from a ChRIS Store.
async def
add_plugin( self, plugin_description: str | dict, compute_resources: Union[str, chris.models.public.ComputeResource, Iterable[Union[chris.models.public.ComputeResource, chris.models.types.ComputeResourceName]]], fname: str = 'Plugin.json') -> chris.models.logged_in.Plugin:
53 async def add_plugin( 54 self, 55 plugin_description: str | dict, 56 compute_resources: str 57 | ComputeResource 58 | Iterable[ComputeResource | ComputeResourceName], 59 fname: str = "Plugin.json", 60 ) -> Plugin: 61 """ 62 Add a plugin to *CUBE*. 63 64 Examples 65 -------- 66 67 ```python 68 cmd = ['docker', 'run', '--rm', 'fnndsc/pl-mri-preview', 'chris_plugin_info'] 69 output = subprocess.check_output(cmd, text=True) 70 desc = json.loads(output) 71 desc['name'] = 'pl-mri-preview' 72 desc['public_repo'] = 'https://github.com/FNNDSC/pl-mri-preview' 73 desc['dock_image'] = 'fnndsc/pl-mri-preview' 74 75 await chris_admin.add_plugin(plugin_description=desc, compute_resources='host') 76 ``` 77 78 The example above is just for show. It's not a good example for several reasons: 79 80 - Calls blocking function `subprocess.check_output` in asynchronous context 81 - It is preferred to use a versioned string for `dock_image` 82 - `host` compute environment is not guaranteed to exist. Instead, you could 83 call `chris.client.authed.AuthenticatedClient.search_compute_resources` 84 or `chris.client.authed.AuthenticatedClient.get_all_compute_resources`: 85 86 ```python 87 all_computes = await chris_admin.get_all_compute_resources() 88 await chris_admin.add_plugin(plugin_description=desc, compute_resources=all_computes) 89 ``` 90 91 Parameters 92 ---------- 93 plugin_description: str | dict 94 JSON description of a plugin. 95 [spec](https://github.com/FNNDSC/CHRIS_docs/blob/5078aaf934bdbe313e85367f88aff7c14730a1d4/specs/ChRIS_Plugins.adoc#descriptor_file) 96 compute_resources 97 Compute resources to register the plugin to. Value can be either a comma-separated `str` of names, 98 a `chris.models.public.ComputeResource`, a sequence of `chris.models.public.ComputeResource`, 99 or a sequence of compute resource names as `str`. 100 fname: str 101 File name to send along in the multi-part POST request. Not important. 102 """ 103 compute_names = _serialize_crs(compute_resources) 104 if not isinstance(plugin_description, str): 105 plugin_description = json.dumps(plugin_description) 106 data = aiohttp.FormData() 107 data.add_field("fname", io.StringIO(plugin_description), filename=fname) 108 data.add_field("compute_names", compute_names) 109 async with self.s.post(self.collection_links.admin, data=data) as res: 110 await raise_for_status(res) 111 return deserialize_linked(self, Plugin, await res.json())
Add a plugin to CUBE.
Examples
cmd = ['docker', 'run', '--rm', 'fnndsc/pl-mri-preview', 'chris_plugin_info']
output = subprocess.check_output(cmd, text=True)
desc = json.loads(output)
desc['name'] = 'pl-mri-preview'
desc['public_repo'] = 'https://github.com/FNNDSC/pl-mri-preview'
desc['dock_image'] = 'fnndsc/pl-mri-preview'
await chris_admin.add_plugin(plugin_description=desc, compute_resources='host')
The example above is just for show. It's not a good example for several reasons:
- Calls blocking function
subprocess.check_output
in asynchronous context - It is preferred to use a versioned string for
dock_image
host
compute environment is not guaranteed to exist. Instead, you could callchris.client.authed.AuthenticatedClient.search_compute_resources
orchris.client.authed.AuthenticatedClient.get_all_compute_resources
:
all_computes = await chris_admin.get_all_compute_resources()
await chris_admin.add_plugin(plugin_description=desc, compute_resources=all_computes)
Parameters
- plugin_description (str | dict): JSON description of a plugin. spec
- compute_resources: Compute resources to register the plugin to. Value can be either a comma-separated
str
of names, achris.models.public.ComputeResource
, a sequence ofchris.models.public.ComputeResource
, or a sequence of compute resource names asstr
. - fname (str): File name to send along in the multi-part POST request. Not important.
async def
create_compute_resource( self, name: Union[str, chris.models.types.ComputeResourceName], compute_url: Union[str, chris.models.types.PfconUrl], compute_user: str, compute_password: str, description: str = None, compute_auth_url: str = None, compute_auth_token: str = None, max_job_exec_seconds: str = None) -> chris.models.public.ComputeResource:
113 async def create_compute_resource( 114 self, 115 name: str | ComputeResourceName, 116 compute_url: str | PfconUrl, 117 compute_user: str, 118 compute_password: str, 119 description: str = None, 120 compute_auth_url: str = None, 121 compute_auth_token: str = None, 122 max_job_exec_seconds: str = None, 123 ) -> ComputeResource: 124 """ 125 Define a new compute resource. 126 """ 127 return await (await self._admin).create_compute_resource( 128 name=name, 129 compute_url=compute_url, 130 compute_user=compute_user, 131 compute_password=compute_password, 132 description=description, 133 compute_auth_url=compute_auth_url, 134 compute_auth_token=compute_auth_token, 135 max_job_exec_seconds=max_job_exec_seconds, 136 )
Define a new compute resource.
Inherited Members
- chris.link.collection_client.CollectionJsonApiClient
- CollectionJsonApiClient
- url
- collection_links
- chris.client.authed.AuthenticatedClient
- from_login
- from_token
- search_feeds
- search_plugins
- plugin_instances
- upload_file
- user
- username
- search_compute_resources
- get_all_compute_resources
- chris.link.linked.Linked
- max_search_requests