addftool 0.2.10__py3-none-any.whl → 0.2.13__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.
- addftool/addf_portal.py +19 -0
- addftool/blob.py +132 -0
- {addftool-0.2.10.dist-info → addftool-0.2.13.dist-info}/METADATA +2 -3
- {addftool-0.2.10.dist-info → addftool-0.2.13.dist-info}/RECORD +7 -7
- {addftool-0.2.10.dist-info → addftool-0.2.13.dist-info}/WHEEL +1 -1
- {addftool-0.2.10.dist-info → addftool-0.2.13.dist-info}/entry_points.txt +0 -0
- {addftool-0.2.10.dist-info → addftool-0.2.13.dist-info}/top_level.txt +0 -0
addftool/addf_portal.py
CHANGED
|
@@ -7,9 +7,28 @@ from addftool.sleep import add_sleep_args, sleep_main
|
|
|
7
7
|
|
|
8
8
|
from addftool.blob import add_blob_args, blob_main
|
|
9
9
|
|
|
10
|
+
# Import version information
|
|
11
|
+
try:
|
|
12
|
+
from importlib.metadata import version
|
|
13
|
+
__version__ = version("addftool")
|
|
14
|
+
except ImportError:
|
|
15
|
+
# Fallback for older Python versions
|
|
16
|
+
import pkg_resources
|
|
17
|
+
__version__ = pkg_resources.get_distribution("addftool").version
|
|
18
|
+
except:
|
|
19
|
+
# Fallback if package is not installed
|
|
20
|
+
__version__ = "0.2.11" # Keep in sync with pyproject.toml
|
|
21
|
+
|
|
10
22
|
|
|
11
23
|
def get_args():
|
|
12
24
|
parser = argparse.ArgumentParser(description="Addf's tool")
|
|
25
|
+
|
|
26
|
+
# Add version argument
|
|
27
|
+
parser.add_argument(
|
|
28
|
+
'--version', '-v',
|
|
29
|
+
action='version',
|
|
30
|
+
version=f'addftool {__version__}'
|
|
31
|
+
)
|
|
13
32
|
|
|
14
33
|
subparsers = parser.add_subparsers(dest='command', help='Sub-command help')
|
|
15
34
|
add_killer_args(subparsers)
|
addftool/blob.py
CHANGED
|
@@ -5,6 +5,8 @@ import json
|
|
|
5
5
|
import yaml
|
|
6
6
|
import tempfile
|
|
7
7
|
from cryptography.fernet import Fernet
|
|
8
|
+
import yaml
|
|
9
|
+
import datetime
|
|
8
10
|
|
|
9
11
|
from .util import execute_command
|
|
10
12
|
|
|
@@ -231,6 +233,128 @@ def get_sas_token_for_blob_url(api_url, blob_url, key, info=False):
|
|
|
231
233
|
return get_sas_token(api_url, an, cn, key, info=info)
|
|
232
234
|
|
|
233
235
|
|
|
236
|
+
def parse_sas_token_from_blobfuse_config(config_file):
|
|
237
|
+
sas_token = None
|
|
238
|
+
account_name = None
|
|
239
|
+
container_name = None
|
|
240
|
+
with open(config_file, 'r') as f:
|
|
241
|
+
try:
|
|
242
|
+
config = yaml.safe_load(f)
|
|
243
|
+
if 'sas' in config["azstorage"] and config["azstorage"]['mode'] == 'sas':
|
|
244
|
+
sas_token = config['azstorage']['sas']
|
|
245
|
+
if 'account-name' in config["azstorage"]:
|
|
246
|
+
account_name = config['azstorage']['account-name']
|
|
247
|
+
if 'container' in config["azstorage"]:
|
|
248
|
+
container_name = config['azstorage']['container']
|
|
249
|
+
else:
|
|
250
|
+
print(f"No 'sas' found in config file: {config_file}")
|
|
251
|
+
except yaml.YAMLError as exc:
|
|
252
|
+
print(exc)
|
|
253
|
+
|
|
254
|
+
if sas_token is None:
|
|
255
|
+
return None, None, None
|
|
256
|
+
|
|
257
|
+
# parse expiry time from sas token
|
|
258
|
+
expiry_time = None
|
|
259
|
+
try:
|
|
260
|
+
sas_parts = sas_token.split('&')
|
|
261
|
+
for part in sas_parts:
|
|
262
|
+
if part.startswith('se='):
|
|
263
|
+
expiry_time = part[3:]
|
|
264
|
+
break
|
|
265
|
+
except Exception as e:
|
|
266
|
+
print(f"Error parsing expiry time from sas token: {e}")
|
|
267
|
+
|
|
268
|
+
# Expiry Time: 2025-10-28T05%3A22Z, convert into timestamp
|
|
269
|
+
if expiry_time is not None:
|
|
270
|
+
try:
|
|
271
|
+
expiry_time = datetime.datetime.strptime(expiry_time, "%Y-%m-%dT%H%%3A%MZ")
|
|
272
|
+
except Exception as e:
|
|
273
|
+
print(f"Error converting expiry time to timestamp: {e}")
|
|
274
|
+
|
|
275
|
+
blob_url = f"https://{account_name}.blob.core.windows.net/{container_name}"
|
|
276
|
+
return sas_token, blob_url, expiry_time
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def update_blobfuse2_yaml_sas_token(config_file, new_sas_token):
|
|
280
|
+
with open(config_file, 'r') as f:
|
|
281
|
+
try:
|
|
282
|
+
config = yaml.safe_load(f)
|
|
283
|
+
except yaml.YAMLError as exc:
|
|
284
|
+
print(exc)
|
|
285
|
+
return False
|
|
286
|
+
|
|
287
|
+
config['azstorage']['sas'] = new_sas_token
|
|
288
|
+
|
|
289
|
+
with open(config_file, 'w') as f:
|
|
290
|
+
try:
|
|
291
|
+
yaml.dump(config, f)
|
|
292
|
+
return True
|
|
293
|
+
except yaml.YAMLError as exc:
|
|
294
|
+
print(exc)
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def update_blobfuse2_config(config_file, api_url, key, hour_threshold=48, view=False):
|
|
299
|
+
is_success = False
|
|
300
|
+
try:
|
|
301
|
+
sas_token, blob_url, expiry_time = parse_sas_token_from_blobfuse_config(config_file)
|
|
302
|
+
if view and blob_url is not None:
|
|
303
|
+
print(f"{blob_url} expiry time: {expiry_time}")
|
|
304
|
+
return False
|
|
305
|
+
if expiry_time is not None:
|
|
306
|
+
now = datetime.datetime.now()
|
|
307
|
+
time_left = expiry_time - now if expiry_time is not None else None
|
|
308
|
+
if time_left is not None and time_left.total_seconds() < 3600 * hour_threshold:
|
|
309
|
+
updated_sas_token = get_sas_token_for_blob_url(api_url, blob_url, key)
|
|
310
|
+
if updated_sas_token:
|
|
311
|
+
is_success = update_blobfuse2_yaml_sas_token(config_file, updated_sas_token)
|
|
312
|
+
except Exception as e:
|
|
313
|
+
print(f"Error updating blobfuse2 config: {e}")
|
|
314
|
+
return False
|
|
315
|
+
return is_success
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def refresh_all_blobfuse2_configs(api_url, key, hour_threshold=48, view=False, selected_mount_paths=None):
|
|
319
|
+
from addftool.process.utils import get_processes
|
|
320
|
+
if not view:
|
|
321
|
+
assert api_url is not None and key is not None, "api url and key must be provided when not in view mode"
|
|
322
|
+
procs = get_processes(command="blobfuse2", contains=False)
|
|
323
|
+
for proc in procs:
|
|
324
|
+
config_file = None
|
|
325
|
+
for arg in proc['command'][1:]:
|
|
326
|
+
if arg.startswith("--config-file="):
|
|
327
|
+
config_file = arg.split("=", 1)[1]
|
|
328
|
+
break
|
|
329
|
+
if selected_mount_paths is not None and config_file is not None:
|
|
330
|
+
mount_path = proc['command'][2]
|
|
331
|
+
# print(f"mount_path: {mount_path}, selected_mount_paths: {selected_mount_paths}")
|
|
332
|
+
if mount_path not in selected_mount_paths:
|
|
333
|
+
continue
|
|
334
|
+
if config_file is not None:
|
|
335
|
+
state = update_blobfuse2_config(config_file, api_url, key, hour_threshold=hour_threshold, view=view)
|
|
336
|
+
if state:
|
|
337
|
+
print(f"Updated SAS token in config file for {' '.join(proc['command'])}")
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def refresh_main(args):
|
|
341
|
+
# only update current user's blobfuse2 configs
|
|
342
|
+
selected_mount_paths = []
|
|
343
|
+
# df -h | grep blobfuse2
|
|
344
|
+
current_user_file_systems = os.popen("df -h | grep blobfuse2").readlines()
|
|
345
|
+
for line in current_user_file_systems:
|
|
346
|
+
parts = line.split()
|
|
347
|
+
if len(parts) >= 6:
|
|
348
|
+
mount_path = parts[5]
|
|
349
|
+
selected_mount_paths.append(mount_path)
|
|
350
|
+
|
|
351
|
+
print(f"selected_mount_paths for current user: {selected_mount_paths}")
|
|
352
|
+
refresh_all_blobfuse2_configs(
|
|
353
|
+
args.api, args.key, hour_threshold=args.hour_threshold,
|
|
354
|
+
view=args.view, selected_mount_paths=selected_mount_paths,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
|
|
234
358
|
def add_args(parser):
|
|
235
359
|
subparsers = parser.add_subparsers(dest='blob_command', help='Sub-command help')
|
|
236
360
|
install_parser = subparsers.add_parser('install', help='Install help')
|
|
@@ -251,6 +375,12 @@ def add_args(parser):
|
|
|
251
375
|
token_parser = subparsers.add_parser('token', help='Token help')
|
|
252
376
|
add_api(token_parser)
|
|
253
377
|
|
|
378
|
+
refresh_parser = subparsers.add_parser('refresh', help='Refresh help')
|
|
379
|
+
refresh_parser.add_argument("-k", "--key", help="f key", type=str)
|
|
380
|
+
refresh_parser.add_argument("-a", "--api", help="api url", type=str)
|
|
381
|
+
refresh_parser.add_argument("-v", "--view", help="view token info", action="store_true")
|
|
382
|
+
refresh_parser.add_argument("-s", "--hour_threshold", help="hour threshold", type=int, default=48)
|
|
383
|
+
|
|
254
384
|
def add_blob_args(subparsers):
|
|
255
385
|
deploy_parser = subparsers.add_parser('blob', help='Blob help')
|
|
256
386
|
add_args(deploy_parser)
|
|
@@ -267,6 +397,8 @@ def blob_main(args):
|
|
|
267
397
|
mount_main(args)
|
|
268
398
|
elif args.blob_command == 'token':
|
|
269
399
|
print(get_token(args, info=False))
|
|
400
|
+
elif args.blob_command == 'refresh':
|
|
401
|
+
refresh_main(args)
|
|
270
402
|
|
|
271
403
|
|
|
272
404
|
def main():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: addftool
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.13
|
|
4
4
|
Requires-Dist: cryptography
|
|
5
5
|
Requires-Dist: requests
|
|
6
6
|
Requires-Dist: PyYAML
|
|
@@ -8,4 +8,3 @@ Requires-Dist: psutil
|
|
|
8
8
|
Requires-Dist: fabric
|
|
9
9
|
Requires-Dist: gevent
|
|
10
10
|
Requires-Dist: parallel-ssh
|
|
11
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
addftool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
addftool/addf_portal.py,sha256=
|
|
3
|
-
addftool/blob.py,sha256=
|
|
2
|
+
addftool/addf_portal.py,sha256=CnOAq3JLQjK9-OyYWDYcmtLBM68L3N6WeP5NjBod4zc,1819
|
|
3
|
+
addftool/blob.py,sha256=prGpDy_esyBL53a5R3yVJdGiXQSPFuU4is1yM9dp2qo,15037
|
|
4
4
|
addftool/broadcast_folder.py,sha256=GQBuSL8Ch537V_fSBHesWyqT3KRYry68pbYOKy2bDj4,19619
|
|
5
5
|
addftool/sleep.py,sha256=kykcZR2tA0ZpRUwQf6IIUdJ4dYkolyD91FdriViq9Nc,11771
|
|
6
6
|
addftool/sync.py,sha256=ZpYxbM8uiPFrV7ODmOaM7asVPCWaxBixA-arVc-1kfs,14045
|
|
@@ -13,8 +13,8 @@ addftool/deploy/vscode_server.py,sha256=tLtSvlcK2fEOaw6udWt8dNELVhwv9F59hF5DJJ-1
|
|
|
13
13
|
addftool/process/__init__.py,sha256=Dze8OrcyjQlAbPrjE_h8bMi8W4b3OJyZOjTucPrkJvM,3721
|
|
14
14
|
addftool/process/utils.py,sha256=JldxnwanLJOgxaPgmCJh7SeBRaaj5rFxWWxh1hpsvbA,2609
|
|
15
15
|
addftool/ssh/__init__.py,sha256=h5_rCO0A6q2Yw9vFguQZZp_ApAJsT1dcnKnbKKZ0cDM,4409
|
|
16
|
-
addftool-0.2.
|
|
17
|
-
addftool-0.2.
|
|
18
|
-
addftool-0.2.
|
|
19
|
-
addftool-0.2.
|
|
20
|
-
addftool-0.2.
|
|
16
|
+
addftool-0.2.13.dist-info/METADATA,sha256=C8_l-dQvZoQ8gkxbP86PYJsfAHzjNiMhBW5lCtq8rCI,221
|
|
17
|
+
addftool-0.2.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
addftool-0.2.13.dist-info/entry_points.txt,sha256=9lkmuWMInwUAtev8w8poNkNd7iML9Bjd5CBCFVxg2b8,111
|
|
19
|
+
addftool-0.2.13.dist-info/top_level.txt,sha256=jqj56-plrBbyzY0tIxB6wPzjAA8kte4hUlajyyQygN4,9
|
|
20
|
+
addftool-0.2.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|