Skip to content

Commit 2acdb92

Browse files
authored
Merge pull request #104 from InfuseAI/feature/group-images-add-remove
[Feature] Add create/delete for group images
2 parents d8bea5f + 3c90639 commit 2acdb92

File tree

3 files changed

+192
-4
lines changed

3 files changed

+192
-4
lines changed

docs/CLI/images.md

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ Usage:
88
Get a image or list images
99
1010
Available Commands:
11-
get Get a image by name
11+
create Create an image
12+
delete Delete an image by name
13+
get Get an image by name
1214
list List images
1315
1416
Options:
@@ -24,9 +26,39 @@ Global Options:
2426
```
2527

2628

29+
### create
30+
31+
Create an image
32+
33+
34+
```
35+
primehub images create
36+
```
37+
38+
39+
* *(optional)* file: The file path of the configurations
40+
41+
42+
43+
44+
### delete
45+
46+
Delete an image by name
47+
48+
49+
```
50+
primehub images delete <name>
51+
```
52+
53+
* name
54+
55+
56+
57+
58+
2759
### get
2860

29-
Get a image by name
61+
Get an image by name
3062

3163

3264
```
@@ -89,4 +121,31 @@ spec:
89121
type: both
90122
url: infuseai/docker-stacks:tensorflow-notebook-v2-5-0-63fdf50a
91123
urlForGpu: infuseai/docker-stacks:tensorflow-notebook-v2-5-0-63fdf50a-gpu-cuda-11
124+
```
125+
126+
Create a group image:
127+
128+
```
129+
$ primehub images create <<EOF
130+
{
131+
"name": "base-notebook-for-group-1",
132+
"displayName": "Base notebook for group 1",
133+
"description": "Base notebook for group 1",
134+
"type": "both",
135+
"url": "infuseai/base-notebook-group-1:v1",
136+
"urlForGpu": "infuseai/base-notebook-group-1:v1"
137+
}
138+
EOF
139+
```
140+
141+
Or you can create a group image from json file:
142+
143+
```
144+
$ primehub images create --file /tmp/base-notebook-group-1.json
145+
```
146+
147+
Delete a group image:
148+
149+
```
150+
$ primehub images delete base-notebook-for-group-1
92151
```

primehub/extras/templates/examples/images.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,30 @@ spec:
3333
url: infuseai/docker-stacks:tensorflow-notebook-v2-5-0-63fdf50a
3434
urlForGpu: infuseai/docker-stacks:tensorflow-notebook-v2-5-0-63fdf50a-gpu-cuda-11
3535
```
36+
37+
Create a group image:
38+
39+
```
40+
$ primehub images create <<EOF
41+
{
42+
"name": "base-notebook-for-group-1",
43+
"displayName": "Base notebook for group 1",
44+
"description": "Base notebook for group 1",
45+
"type": "both",
46+
"url": "infuseai/base-notebook-group-1:v1",
47+
"urlForGpu": "infuseai/base-notebook-group-1:v1"
48+
}
49+
EOF
50+
```
51+
52+
Or you can create a group image from json file:
53+
54+
```
55+
$ primehub images create --file /tmp/base-notebook-group-1.json
56+
```
57+
58+
Delete a group image:
59+
60+
```
61+
$ primehub images delete base-notebook-for-group-1
62+
```

primehub/images.py

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import json
12
from typing import Optional
23

3-
from primehub import Helpful, cmd, Module
4+
from primehub import Helpful, cmd, Module, primehub_load_config
5+
from primehub.utils import PrimeHubException
6+
from primehub.utils.optionals import file_flag
47
from primehub.resource_operations import GroupResourceOperation
8+
from primehub.utils.validator import validate_name
59

610

711
class Images(Helpful, Module, GroupResourceOperation):
@@ -37,7 +41,7 @@ def list(self) -> list:
3741
"""
3842
return self.do_list(Images.query, Images.resource_name)
3943

40-
@cmd(name='get', description='Get a image by name', return_required=True)
44+
@cmd(name='get', description='Get an image by name', return_required=True)
4145
def get(self, name) -> Optional[dict]:
4246
"""
4347
Get an image from the current group
@@ -50,5 +54,103 @@ def get(self, name) -> Optional[dict]:
5054
"""
5155
return self.do_get(Images.query, Images.resource_name, name)
5256

57+
@cmd(name='create', description='Create an image', optionals=[('file', file_flag)])
58+
def _create_cmd(self, **kwargs):
59+
"""
60+
Create an image for the current group
61+
62+
:type file: str
63+
:param file: The file path of the configurations
64+
65+
:rtype dict
66+
:return The image
67+
"""
68+
config = primehub_load_config(filename=kwargs.get('file', None))
69+
if not config:
70+
invalid_config('The configuration is required.')
71+
72+
return self.create(config)
73+
74+
def create(self, config):
75+
"""
76+
Create an image for the current group
77+
78+
:type config: dict
79+
:param config: The configurations for creating an image
80+
81+
:rtype dict
82+
:return The image
83+
"""
84+
payload = validate(config)
85+
payload['groups'] = {'connect': [{'id': self.group_id}]}
86+
payload['groupName'] = self.group_name
87+
88+
query = """
89+
mutation CreateImageMutation($data: ImageCreateInput!) {
90+
createImage(data: $data) {
91+
id
92+
}
93+
}
94+
"""
95+
96+
results = self.request({'data': payload}, query)
97+
if 'data' not in results:
98+
return results
99+
return results['data']['createImage']
100+
101+
@cmd(name='delete', description='Delete an image by name', return_required=True)
102+
def delete(self, name):
103+
"""
104+
Delete an image by id
105+
106+
:type id: str
107+
:param id: the id of an image
108+
109+
:rtype dict
110+
:return an image
111+
"""
112+
113+
query = """
114+
mutation DeleteImageMutation($where: ImageWhereUniqueInput!) {
115+
deleteImage(where: $where) {
116+
id
117+
}
118+
}
119+
"""
120+
self.get(name)
121+
122+
results = self.request({'where': {'id': name}}, query)
123+
if 'data' not in results:
124+
return results
125+
return results['data']['deleteImage']
126+
53127
def help_description(self):
54128
return "Get a image or list images"
129+
130+
131+
def validate(payload: dict, for_update=False):
132+
if not for_update:
133+
validate_name(payload)
134+
135+
image_type = payload.get('type')
136+
if image_type is not None and image_type not in ['cpu', 'gpu', 'both']:
137+
raise PrimeHubException("type should be one of ['cpu', 'gpu', 'both']")
138+
url = payload.get('url')
139+
if url is None:
140+
raise PrimeHubException("url is required")
141+
142+
return payload
143+
144+
145+
def invalid_config(message: str):
146+
example = """
147+
{
148+
"name": "base",
149+
"displayName": "Base image",
150+
"description": "base-notebook with python 3.7",
151+
"type": "both",
152+
"url": "infuseai/docker-stacks:base-notebook-63fdf50a",
153+
"urlForGpu": "infuseai/docker-stacks:base-notebook-63fdf50a-gpu"
154+
}
155+
""".strip()
156+
raise PrimeHubException(message + "\n\nExample:\n" + json.dumps(json.loads(example), indent=2))

0 commit comments

Comments
 (0)