Skip to content

Commit 6eca469

Browse files
authored
Merge pull request #13 from algorithmiaio/mm-failover
Supporting manifest file failover
2 parents 9ddd7f8 + 0893540 commit 6eca469

File tree

4 files changed

+37
-21
lines changed

4 files changed

+37
-21
lines changed

adk/ADK.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def __init__(self, apply_func, load_func=None, client=None):
3838
self.is_local = not os.path.exists(self.FIFO_PATH)
3939
self.load_result = None
4040
self.loading_exception = None
41-
self.manifest_path = "model_manifest.json.freeze"
41+
self.manifest_path = "model_manifest.json"
4242
self.model_data = self.init_manifest(self.manifest_path)
4343

4444
def init_manifest(self, path):

adk/modeldata.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66

77
class ModelData(object):
88
def __init__(self, client, model_manifest_path):
9-
self.manifest_freeze_path = model_manifest_path
10-
self.manifest_data = get_manifest(self.manifest_freeze_path)
9+
self.manifest_path = model_manifest_path
10+
self.manifest_freeze_path = "{}.freeze".format(self.manifest_path)
11+
self.manifest_data = get_manifest(self.manifest_freeze_path, self.manifest_path)
1112
self.client = client
1213
self.models = {}
1314
self.usr_key = "__user__"
@@ -27,7 +28,6 @@ def data(self):
2728
output[without_usr_key] = __dict[key]
2829
return output
2930

30-
3131
def available(self):
3232
if self.manifest_data:
3333
return True
@@ -39,14 +39,16 @@ def initialize(self):
3939
raise Exception("Client was not defined, please define a Client when using Model Manifests.")
4040
for required_file in self.manifest_data['required_files']:
4141
name = required_file['name']
42+
source_uri = required_file['source_uri']
43+
fail_on_tamper = required_file.get('fail_on_tamper', False)
44+
expected_hash = required_file.get('md5_checksum', None)
4245
if name in self.models:
4346
raise Exception("Duplicate 'name' detected. \n"
4447
+ name + " was found to be used by more than one data file, please rename.")
45-
expected_hash = required_file['md5_checksum']
46-
with self.client.file(required_file['source_uri']).getFile() as f:
48+
with self.client.file(source_uri).getFile() as f:
4749
local_data_path = f.name
4850
real_hash = md5_for_file(local_data_path)
49-
if real_hash != expected_hash and required_file['fail_on_tamper']:
51+
if real_hash != expected_hash and fail_on_tamper:
5052
raise Exception("Model File Mismatch for " + name +
5153
"\nexpected hash: " + expected_hash + "\nreal hash: " + real_hash)
5254
else:
@@ -70,32 +72,46 @@ def find_optional_model(self, file_name):
7072
raise Exception("file with name '" + file_name + "' not found in model manifest.")
7173
model_info = found_models[0]
7274
self.models[file_name] = {}
73-
expected_hash = model_info['md5_checksum']
74-
with self.client.file(model_info['source_uri']).getFile() as f:
75+
source_uri = model_info['source_uri']
76+
fail_on_tamper = model_info.get("fail_on_tamper", False)
77+
expected_hash = model_info.get('md5_checksum', None)
78+
with self.client.file(source_uri).getFile() as f:
7579
local_data_path = f.name
7680
real_hash = md5_for_file(local_data_path)
77-
if real_hash != expected_hash and model_info['fail_on_tamper']:
81+
if real_hash != expected_hash and fail_on_tamper:
7882
raise Exception("Model File Mismatch for " + file_name +
7983
"\nexpected hash: " + expected_hash + "\nreal hash: " + real_hash)
8084
else:
8185
self.models[file_name] = FileData(real_hash, local_data_path)
8286

8387

84-
def get_manifest(manifest_path):
85-
if os.path.exists(manifest_path):
86-
with open(manifest_path) as f:
88+
def get_manifest(manifest_frozen_path, manifest_reg_path):
89+
if os.path.exists(manifest_frozen_path):
90+
with open(manifest_frozen_path) as f:
8791
manifest_data = json.load(f)
88-
expected_lock_checksum = manifest_data.get('lock_checksum')
89-
del manifest_data['lock_checksum']
90-
detected_lock_checksum = md5_for_str(str(manifest_data))
91-
if expected_lock_checksum != detected_lock_checksum:
92+
if check_lock(manifest_data):
93+
return manifest_data
94+
else:
9295
raise Exception("Manifest FreezeFile Tamper Detected; please use the CLI and 'algo freeze' to rebuild your "
9396
"algorithm's freeze file.")
97+
elif os.path.exists(manifest_reg_path):
98+
with open(manifest_reg_path) as f:
99+
manifest_data = json.load(f)
94100
return manifest_data
95101
else:
96102
return None
97103

98104

105+
def check_lock(manifest_data):
106+
expected_lock_checksum = manifest_data.get('lock_checksum')
107+
del manifest_data['lock_checksum']
108+
detected_lock_checksum = md5_for_str(str(manifest_data))
109+
if expected_lock_checksum != detected_lock_checksum:
110+
return False
111+
else:
112+
return True
113+
114+
99115
def md5_for_file(fname):
100116
hash_md5 = hashlib.md5()
101117
with open(fname, "rb") as f:

tests/test_adk_local.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def execute_example(self, input, apply, load=None):
2323
algo.init(input, pprint=lambda x: output.append(x))
2424
return output[0]
2525

26-
def execute_manifest_example(self, input, apply, load, manifest_path="manifests/good_model_manifest.json.freeze"):
26+
def execute_manifest_example(self, input, apply, load, manifest_path):
2727
client = Algorithmia.client()
2828
algo = ADKTest(apply, load, manifest_path=manifest_path, client=client)
2929
output = []
@@ -131,7 +131,7 @@ def test_manifest_file_success(self):
131131
actual_output = json.loads(self.execute_manifest_example(input, apply_successful_manifest_parsing,
132132
loading_with_manifest,
133133
manifest_path="tests/manifests/good_model_manifest"
134-
".json.freeze"))
134+
".json"))
135135
self.assertEqual(expected_output, actual_output)
136136

137137
def test_manifest_file_tampered(self):
@@ -145,7 +145,7 @@ def test_manifest_file_tampered(self):
145145
actual_output = json.loads(self.execute_manifest_example(input, apply_successful_manifest_parsing,
146146
loading_with_manifest,
147147
manifest_path="tests/manifests/bad_model_manifest"
148-
".json.freeze"))
148+
".json"))
149149
self.assertEqual(expected_output, actual_output)
150150

151151

tests/test_adk_remote.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def test_manifest_file_success(self):
173173
actual_output = self.execute_manifest_example(input, apply_successful_manifest_parsing,
174174
loading_with_manifest,
175175
manifest_path="tests/manifests/good_model_manifest"
176-
".json.freeze")
176+
".json")
177177
self.assertEqual(expected_output, actual_output)
178178

179179

0 commit comments

Comments
 (0)