Skip to content

Commit 0af4b5c

Browse files
committed
add methods for the /api/v0/files/ endpoints
1 parent 81ce4d6 commit 0af4b5c

File tree

1 file changed

+143
-1
lines changed

1 file changed

+143
-1
lines changed

missioncontrol_client/__init__.py

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,41 @@
11
import argparse
2+
import datetime
3+
import io
24
import json
35
import os
6+
import socket
7+
import zlib
48
from urllib.parse import urljoin
9+
from uuid import uuid4
510

11+
import pytz
612
import requests
13+
from datalake import GzippingFile
14+
15+
16+
class UTC(object):
17+
# TODO factor this out into a proper library
18+
19+
def __init__(self, d="now"):
20+
if d == "now":
21+
self._d = datetime.datetime.utcnow()
22+
elif isinstance(d, datetime.datetime):
23+
if not d.tzinfo:
24+
# naive, assume UTC
25+
d = d.replace(tzinfo=pytz.utc)
26+
elif d.tzinfo == pytz.utc:
27+
pass
28+
else:
29+
d = d.astimezone(pytz.utc)
30+
self._d = d
31+
else:
32+
# TODO convert strings, etc
33+
raise NotImplementedError()
34+
35+
@property
36+
def iso(self):
37+
d = self._d.isoformat('T', 'microseconds')
38+
return d.replace("+00:00", "Z")
739

840

941
class MCAPI(object):
@@ -13,6 +45,17 @@ def __init__(self, mc_base, jwt=None):
1345
self.s = requests.session()
1446
self.jwt = None
1547

48+
@classmethod
49+
def from_environ(cls, ignore_ssl=False):
50+
mc_api = cls(os.environ['MC_BASE'])
51+
if ignore_ssl:
52+
mc_api.s.verify = False
53+
if os.environ.get('MC_JWT'):
54+
mc_api.login(jwt=os.environ['MC_JWT'])
55+
else:
56+
mc_api.login(username=os.environ['MC_USERNAME'], password=os.environ['MC_PASSWORD'])
57+
return mc_api
58+
1659
def get(self, path, *args, **kwargs):
1760
r = self.s.get(urljoin(self.mc_base, path), *args, **kwargs)
1861
r.raise_for_status()
@@ -22,6 +65,16 @@ def getj(self, path, *args, **kwargs):
2265
r = self.get(path, *args, **kwargs)
2366
return r.json()
2467

68+
def post(self, path, *args, **kwargs):
69+
r = self.s.post(urljoin(self.mc_base, path), *args, **kwargs)
70+
r.raise_for_status()
71+
return r
72+
73+
def postj(self, path, *args, **kwargs):
74+
ret = self.s.post(urljoin(self.mc_base, path), *args, **kwargs)
75+
ret.raise_for_status()
76+
return ret.json()
77+
2578
def put(self, path, *args, **kwargs):
2679
r = self.s.put(urljoin(self.mc_base, path), *args, **kwargs)
2780
r.raise_for_status()
@@ -145,6 +198,94 @@ def get_pass_task_stack(self, uuid, **kwargs):
145198
json=kwargs
146199
)
147200

201+
def get_latest_file(self, what, where, **kwargs):
202+
return self.getj(
203+
f'/api/v0/files/latest/{what}/{where}/',
204+
params=kwargs
205+
)
206+
207+
def get_files(self, what, **kwargs):
208+
kwargs.update({"what": what})
209+
return self.getj(
210+
f'/api/v0/files/search/',
211+
params=kwargs
212+
)
213+
214+
def get_files_by_cid(self, cid, **kwargs):
215+
return self.getj(
216+
f'/api/v0/files/cid/{cid}/',
217+
params=kwargs
218+
)
219+
220+
def get_files_by_work_id(self, work_id, **kwargs):
221+
return self.getj(
222+
f'/api/v0/files/work-id/{work_id}/',
223+
params=kwargs
224+
)
225+
226+
def get_file(self, uuid):
227+
return self.getj(
228+
f'/api/v0/files/{uuid}/'
229+
)
230+
231+
def download_file(self, uuid):
232+
return self.get(
233+
f'/api/v0/files/{uuid}/data/'
234+
)
235+
236+
def download_cid(self, cid):
237+
return self.get(
238+
f'/api/v0/raw-file/{cid}/data/'
239+
)
240+
241+
def upload_file(self, path, what, uuid=None, where=None, start=None,
242+
end=None, work_id=None, content_type=None):
243+
244+
if uuid is None:
245+
uuid = str(uuid4())
246+
247+
if start is None:
248+
start = UTC("now").iso
249+
else:
250+
start = UTC(start).iso
251+
252+
if where is None:
253+
where = socket.getfqdn()
254+
255+
f = GzippingFile.from_filename(
256+
path,
257+
what=what,
258+
where=where,
259+
start=start,
260+
work_id=work_id
261+
)
262+
263+
# get signed upload
264+
signed = self.postj(
265+
f'/api/v0/files/presign/',
266+
json=f.metadata
267+
)
268+
269+
file_tuple = ("file", f)
270+
if content_type is not None:
271+
file_tuple += (content_type,)
272+
273+
# upload file
274+
if "url" in signed:
275+
signed["fields"]["Content-Encoding"] = "gzip"
276+
resp = requests.post(
277+
signed["url"],
278+
data=signed["fields"],
279+
files=[file_tuple]
280+
)
281+
resp.raise_for_status()
282+
283+
# upload metadata
284+
return self.putj(
285+
f'/api/v0/files/{uuid}/',
286+
json=f.metadata
287+
)
288+
148289
def login(self, username=None, password=None, jwt=None):
149290
if username is not None and jwt is not None:
150291
raise ValueError("Can't give both a username and a jwt")
@@ -213,6 +354,7 @@ def handle_default_args(args):
213354
args.mc_api.login(username=args.username, password=args.password)
214355

215356
def from_environ(ignore_ssl=False):
357+
# deprecated, use MCAPI.from_environ()
216358
mc_api = MCAPI(os.environ['MC_BASE'])
217359
if ignore_ssl:
218360
mc_api.s.verify = False
@@ -221,4 +363,4 @@ def from_environ(ignore_ssl=False):
221363
else:
222364
mc_api.login(username=os.environ['MC_USERNAME'], password=os.environ['MC_PASSWORD'])
223365

224-
return mc_api
366+
return mc_api

0 commit comments

Comments
 (0)