Skip to content

Commit dd2fc81

Browse files
committed
Update with new indexing method
1 parent 70aca2b commit dd2fc81

File tree

1 file changed

+115
-50
lines changed

1 file changed

+115
-50
lines changed

python/make_vcsp_2018.py

Lines changed: 115 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""
44

55
__author__ = 'VMware, Inc.'
6-
__copyright__ = 'Copyright 2018 VMware, Inc. All rights reserved.'
6+
__copyright__ = 'Copyright 2019 VMware, Inc. All rights reserved.'
77

88
import argparse
99
import boto3
@@ -68,18 +68,51 @@ def _make_lib(name, id=uuid.uuid4(), creation=datetime.datetime.now(), version=1
6868

6969

7070
def _make_item(directory, vcsp_type, name, files, description="", properties={},
71-
identifier=uuid.uuid4(), creation=datetime.datetime.now(), version=2):
72-
return {
73-
"created": creation.strftime(ISO_FORMAT),
74-
"description": description,
75-
"version": str(version),
76-
"files": files,
77-
"id": "urn:uuid:%s" % identifier,
78-
"name": name,
79-
"properties": properties,
80-
"selfHref": "%s/%s" % (directory, ITEM_FILE),
81-
"type": vcsp_type
82-
}
71+
identifier=uuid.uuid4(), creation=datetime.datetime.now(), version=2,
72+
library_id="", is_vapp_template="false"):
73+
'''
74+
add type adapter metadata for OVF template
75+
'''
76+
if "urn:uuid:" not in str(identifier):
77+
item_id = "urn:uuid:%s" % identifier
78+
else:
79+
item_id = identifier
80+
type_metadata = None
81+
if vcsp_type == VCSP_TYPE_OVF:
82+
# generate sample type metadata for OVF template so that subscriber can show OVF VM type
83+
type_metadata_value = "{\"id\":\"%s\",\"version\":\"%s\",\"libraryIdParent\":\"%s\",\"isVappTemplate\":\"%s\",\"vmTemplate\":null,\"vappTemplate\":null,\"networks\":[],\"storagePolicyGroups\":null}" % (item_id, str(version), library_id, is_vapp_template)
84+
type_metadata = {
85+
"key": "type-metadata",
86+
"value": type_metadata_value,
87+
"type": "String",
88+
"domain": "SYSTEM",
89+
"visibility": "READONLY"
90+
}
91+
if type_metadata:
92+
return {
93+
"created": creation.strftime(ISO_FORMAT),
94+
"description": description,
95+
"version": str(version),
96+
"files": files,
97+
"id": item_id,
98+
"name": name,
99+
"metadata": [type_metadata],
100+
"properties": properties,
101+
"selfHref": "%s/%s" % (directory, ITEM_FILE),
102+
"type": vcsp_type
103+
}
104+
else:
105+
return {
106+
"created": creation.strftime(ISO_FORMAT),
107+
"description": description,
108+
"version": str(version),
109+
"files": files,
110+
"id": item_id,
111+
"name": name,
112+
"properties": properties,
113+
"selfHref": "%s/%s" % (directory, ITEM_FILE),
114+
"type": vcsp_type
115+
}
83116

84117

85118
def _make_items(items, version=1):
@@ -88,7 +121,7 @@ def _make_items(items, version=1):
88121
}
89122

90123

91-
def _dir2item(path, directory, md5_enabled):
124+
def _dir2item(path, directory, md5_enabled, lib_id):
92125
files_items = []
93126
name = os.path.split(path)[-1]
94127
vcsp_type = VCSP_TYPE_OTHER
@@ -111,6 +144,8 @@ def _dir2item(path, directory, md5_enabled):
111144
m.update(os.path.dirname(p).encode('utf-8'))
112145
if ".ovf" in p:
113146
vcsp_type = VCSP_TYPE_OVF
147+
# TODO: ready ovf descriptor for type metadata
148+
is_vapp = "false"
114149
elif ".iso" in p:
115150
vcsp_type = VCSP_TYPE_ISO
116151
size = os.path.getsize(p)
@@ -125,10 +160,10 @@ def _dir2item(path, directory, md5_enabled):
125160
"etag": folder_md5,
126161
"hrefs": [ href ]
127162
})
128-
return _make_item(name, vcsp_type, name, files_items, identifier = uuid.uuid4())
163+
return _make_item(name, vcsp_type, name, files_items, identifier = uuid.uuid4(), library_id=lib_id, is_vapp_template=is_vapp)
129164

130165

131-
def _dir2item_s3(s3_client, bucket_name, path, item_name, skip_cert):
166+
def _dir2item_s3(s3_client, bucket_name, path, item_name, skip_cert, lib_id, old_item=""):
132167
"""
133168
Generate items jsons for the given item path on s3
134169
@@ -142,22 +177,35 @@ def _dir2item_s3(s3_client, bucket_name, path, item_name, skip_cert):
142177
path: item path on S3 bucket
143178
item_name: name of the item
144179
skip_cert: whether or not to skip cert file
180+
lib_id: library id
181+
old_item: old item json
145182
146183
Returns:
147184
map of item name to item json
148185
"""
149-
items_jsons = {}
186+
items_json = {}
150187
files_items = []
151188
vcsp_type = None
152189
response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix=path, Delimiter="/")
153190

191+
is_vapp = "false"
154192
for content in response['Contents']:
155193
file_path = content['Key']
156194
if file_path == path or file_path.endswith("item.json"):
157195
continue
158196
file_name = file_path.split("/")[-1]
159197
if ".ovf" in file_name:
160198
vcsp_type = VCSP_TYPE_OVF
199+
# check if the existing item json already contains "type-metadata" metadata, if not
200+
# download the OVF file and parse the descriptor for metadata and search for "<VirtualSystemCollection"
201+
if "type-metadata" not in old_item:
202+
try:
203+
s3_ovf_obj = s3_client.get_object(Bucket=bucket_name, Key=file_path)
204+
ovf_desc = s3_ovf_obj['Body'].read().decode('utf-8')
205+
if "<VirtualSystemCollection" in ovf_desc:
206+
is_vapp = "true"
207+
except:
208+
logger.error("Failed to read ovf descriptor: %s" % file_path)
161209
if vcsp_type != VCSP_TYPE_OVF and ".iso" not in file_name:
162210
vcsp_type = VCSP_TYPE_OTHER
163211
if vcsp_type not in [VCSP_TYPE_OVF, VCSP_TYPE_OTHER] and ".iso" in file_name:
@@ -168,7 +216,7 @@ def _dir2item_s3(s3_client, bucket_name, path, item_name, skip_cert):
168216
file_name = file_path.split("/")[-1]
169217
href = "%s/%s" % (item_name, file_name)
170218

171-
if file_path == path or file_path.endswith("item.json"):
219+
if file_path == path or file_path.endswith("item.json"):
172220
continue # skip the item folder and item.json meta data file
173221

174222
size = content['Size']
@@ -186,17 +234,23 @@ def _dir2item_s3(s3_client, bucket_name, path, item_name, skip_cert):
186234
child_item_name = file_name[:extension_index]
187235
# note: it is not necessary to create a child iso item folder if not exist
188236
item_path = item_name + "/" + child_item_name
189-
items_jsons[child_item_name] = _make_item(item_path, vcsp_type, child_item_name, [file_json], identifier = uuid.uuid4())
237+
items_json[child_item_name] = _make_item(item_path, vcsp_type, child_item_name, [file_json], identifier = uuid.uuid4())
190238
else:
191239
if vcsp_type == VCSP_TYPE_OVF and file_name.endswith(FILE_EXTENSION_CERT) and skip_cert:
192240
# skip adding cert file if skip_cert is true
193241
continue
194242
files_items.append(file_json)
195243

196244
if vcsp_type != VCSP_TYPE_ISO:
197-
items_jsons[item_name] = _make_item(item_name, vcsp_type, item_name, files_items, identifier = uuid.uuid4())
245+
identifier = uuid.uuid4()
246+
if old_item != "":
247+
identifier = old_item["id"]
248+
items_json[item_name] = _make_item(item_name, vcsp_type, item_name, files_items, identifier = identifier, library_id=lib_id, is_vapp_template=is_vapp)
249+
if vcsp_type == VCSP_TYPE_OVF and "type-metadata" in old_item:
250+
# TODO: avoid other item metadata update
251+
items_json[item_name]["metadata"] = old_item["metadata"]
198252

199-
return items_jsons
253+
return items_json
200254

201255

202256
def make_vcsp(lib_name, lib_path, md5_enabled):
@@ -241,21 +295,21 @@ def make_vcsp(lib_name, lib_path, md5_enabled):
241295
p = os.path.join(lib_path, item_path)
242296
if not os.path.isdir(p):
243297
continue # not interesting
244-
items_json = _dir2item(p, item_path, md5_enabled)
298+
item_json = _dir2item(p, item_path, md5_enabled, "urn:uuid:%s" % lib_id)
245299
if item_path not in old_items and updating_lib:
246300
changed = True
247301
elif item_path in old_items:
248302
file_changed = False
249-
items_json["id"] = old_items[item_path]["id"]
250-
items_json["created"] = old_items[item_path]["created"]
251-
items_json["version"] = old_items[item_path]["version"]
252-
file_names = set([i["name"] for i in items_json["files"]])
303+
item_json["id"] = old_items[item_path]["id"]
304+
item_json["created"] = old_items[item_path]["created"]
305+
item_json["version"] = old_items[item_path]["version"]
306+
file_names = set([i["name"] for i in item_json["files"]])
253307
old_file_names = set([i["name"] for i in old_items[item_path]["files"]])
254308
if file_names != old_file_names:
255309
# files added or removed
256310
changed = True
257311
file_changed = True
258-
for f in items_json["files"]:
312+
for f in item_json["files"]:
259313
if file_changed:
260314
break
261315
for old_f in old_items[item_path]["files"]:
@@ -264,13 +318,13 @@ def make_vcsp(lib_name, lib_path, md5_enabled):
264318
file_changed = True
265319
break
266320
if file_changed:
267-
item_version = int(items_json["version"])
268-
items_json["version"] = str(item_version + 1)
321+
item_version = int(item_json["version"])
322+
item_json["version"] = str(item_version + 1)
269323
del old_items[item_path]
270324
json_item_file = ''.join((p, os.sep, ITEM_FILE))
271325
with open(json_item_file, "w") as f:
272-
json.dump(items_json, f, indent=2)
273-
items.append(items_json)
326+
json.dump(item_json, f, indent=2)
327+
items.append(item_json)
274328

275329
if updating_lib and len(old_items) != 0:
276330
changed = True # items were removed
@@ -361,36 +415,43 @@ def make_vcsp_s3(lib_name, lib_path, skip_cert):
361415

362416
items = []
363417
changed = False
418+
update_items_json = False
364419

365420
response = s3_client.list_objects_v2(Bucket=bucket_name, Prefix=lib_folder_path, Delimiter="/")
366421
if response['CommonPrefixes']:
367422
# skip items generation if no child folders
368423
for child in response['CommonPrefixes']:
369424
p = child['Prefix']
370425
item_path = p.split("/")[-2]
371-
items_jsons = _dir2item_s3(s3_client, bucket_name, p, item_path, skip_cert)
426+
old_item = ""
427+
if item_path in old_items:
428+
old_item = old_items[item_path]
429+
items_json = _dir2item_s3(s3_client, bucket_name, p, item_path, skip_cert, "urn:uuid:%s" % lib_id, old_item)
372430

373-
for item_path, items_json in items_jsons.items():
374-
items_json["contentVersion"] = '2' # default to content version 2
431+
for item_path, item_json in items_json.items():
432+
item_json["contentVersion"] = '2' # default to content version 2
375433
if item_path not in old_items and updating_lib:
376434
changed = True
377435
elif item_path in old_items:
378436
file_changed = False
379-
items_json["id"] = old_items[item_path]["id"]
380-
items_json["created"] = old_items[item_path]["created"]
381-
items_json["version"] = old_items[item_path]["version"]
437+
item_json["id"] = old_items[item_path]["id"]
438+
item_json["created"] = old_items[item_path]["created"]
439+
item_json["version"] = old_items[item_path]["version"]
382440
if "contentVersion" in old_items[item_path]:
383-
items_json["contentVersion"] = old_items[item_path]["contentVersion"]
441+
item_json["contentVersion"] = old_items[item_path]["contentVersion"]
384442
else:
385443
changed = True
386444

387-
file_names = set([i["name"] for i in items_json["files"]])
445+
if "type-metadata" not in str(old_items[item_path]) and "type-metadata" in str(item_json):
446+
update_items_json = True
447+
448+
file_names = set([i["name"] for i in item_json["files"]])
388449
old_file_names = set([i["name"] for i in old_items[item_path]["files"]])
389450
if file_names != old_file_names:
390451
# files added or removed
391452
changed = True
392453
file_changed = True
393-
for f in items_json["files"]:
454+
for f in item_json["files"]:
394455
if file_changed:
395456
break
396457
for old_f in old_items[item_path]["files"]:
@@ -400,15 +461,15 @@ def make_vcsp_s3(lib_name, lib_path, skip_cert):
400461
break
401462
if file_changed:
402463
# bump up version and content version
403-
item_version = int(items_json["version"])
404-
items_json["version"] = str(item_version + 1)
405-
item_content_version = int(items_json["contentVersion"])
406-
items_json["contentVersion"] = str(item_content_version + 1)
464+
item_version = int(item_json["version"])
465+
item_json["version"] = str(item_version + 1)
466+
item_content_version = int(item_json["contentVersion"])
467+
item_json["contentVersion"] = str(item_content_version + 1)
407468
del old_items[item_path]
408-
json_item_file = lib_folder_path + items_json['selfHref']
469+
json_item_file = lib_folder_path + item_json['selfHref']
409470
obj = s3.Object(bucket_name, json_item_file)
410-
obj.put(Body=json.dumps(items_json, indent=2))
411-
items.append(items_json)
471+
obj.put(Body=json.dumps(item_json, indent=2))
472+
items.append(item_json)
412473

413474
if updating_lib and len(old_items) != 0:
414475
changed = True # items were removed, and delete old iso item folders
@@ -424,7 +485,11 @@ def make_vcsp_s3(lib_name, lib_path, skip_cert):
424485
objects.delete()
425486

426487
if updating_lib and not changed:
427-
logger.info("Nothing to update, quitting")
488+
logger.info("Nothing to update on the library")
489+
if update_items_json:
490+
logger.info("items json needs to be updated, updating items json...")
491+
obj = s3.Object(bucket_name, lib_items_json_path)
492+
obj.put(Body=json.dumps(_make_items(items, lib_version), indent=2))
428493
return
429494
if changed:
430495
lib_version = int(lib_version)
@@ -482,8 +547,8 @@ def usage():
482547
'''
483548
The usage message for the argument parser.
484549
'''
485-
return """Usage: python make-vcsp-2018.py -n <library-name> -t <storage-type:local or s3, default local> -p <library-storage-path> --etag <true or false, default true>
486-
--skip-cert <true or fale, default true
550+
return """Usage: python vcsp_maker.py -n <library-name> -t <storage-type:local or s3, default local> -p <library-storage-path> --etag <true or false, default true>
551+
--skip-cert <true or fale, default true>
487552
488553
Note that s3 requires the following configurations:
489554
1. ~/.aws/config

0 commit comments

Comments
 (0)