114 lines
3.6 KiB
Python
Executable File
114 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import json
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import tarfile
|
|
import logging
|
|
import base64
|
|
import cbor
|
|
|
|
ENTITY_FILENAME_SUFFIX = '-entity.tar.gz'
|
|
|
|
EXPECTED_FILES = [
|
|
'entity/entity.json',
|
|
'entity/entity_genesis.json',
|
|
'node/node_genesis.json',
|
|
]
|
|
|
|
logger = logging.getLogger('unpack_entities')
|
|
|
|
|
|
# May want a more granular error in the future
|
|
class InvalidEntitiesDetected(Exception):
|
|
pass
|
|
|
|
|
|
def unpack_entities(src_entities_dir_path, dest_entities_dir_path):
|
|
invalid_entity_packages = []
|
|
# Unpack all of the entity packages in the form of `*-entity.tar.gz`. Also
|
|
# unpack the entities in lexicographical order so it is potentially easier
|
|
# to read logs.
|
|
for filename in sorted(os.listdir(src_entities_dir_path)):
|
|
if filename.endswith(ENTITY_FILENAME_SUFFIX):
|
|
entity_owner = filename[:-len(ENTITY_FILENAME_SUFFIX)]
|
|
|
|
unpacked_entity_dir_path = os.path.join(
|
|
dest_entities_dir_path,
|
|
entity_owner
|
|
)
|
|
# Create the new entity directory
|
|
logger.info('Unpack package for entity owner "%s"' % entity_owner)
|
|
os.mkdir(unpacked_entity_dir_path)
|
|
|
|
package = tarfile.open(os.path.join(src_entities_dir_path,
|
|
filename))
|
|
package.extractall(unpacked_entity_dir_path)
|
|
|
|
if not validate_entity_package(unpacked_entity_dir_path):
|
|
invalid_entity_packages.append(entity_owner)
|
|
else:
|
|
logger.info('Entity owned by "%s" is valid' % entity_owner)
|
|
|
|
if len(invalid_entity_packages) > 0:
|
|
for entity_owner in invalid_entity_packages:
|
|
logger.error('Invalid Entity for %s' % entity_owner)
|
|
raise InvalidEntitiesDetected()
|
|
|
|
|
|
def validate_entity_package(package_path):
|
|
is_valid = True
|
|
# Validate that the expected directory structure exists
|
|
for expected_file_name in EXPECTED_FILES:
|
|
expected_file_path = os.path.join(package_path, expected_file_name)
|
|
|
|
if not os.path.isfile(expected_file_path):
|
|
logger.warning('Expected file "%s" missing' % expected_file_path)
|
|
is_valid = False
|
|
|
|
if not is_valid:
|
|
return is_valid
|
|
|
|
# Ensure that the node is properly loaded into the
|
|
# FIXME we should do this check using something written with oasis-core as a
|
|
# library. This is quick and dirty.
|
|
entity_genesis_path = os.path.join(
|
|
package_path, 'entity/entity_genesis.json')
|
|
node_genesis_path = os.path.join(package_path, 'node/node_genesis.json')
|
|
|
|
with open(entity_genesis_path) as entity_genesis_file:
|
|
entity_genesis = json.load(entity_genesis_file)
|
|
|
|
with open(node_genesis_path) as node_genesis_file:
|
|
node_genesis = json.load(node_genesis_file)
|
|
|
|
entity_descriptor = cbor.loads(base64.b64decode(
|
|
entity_genesis['untrusted_raw_value']))
|
|
node_descriptor = cbor.loads(
|
|
base64.b64decode(node_genesis['untrusted_raw_value']))
|
|
|
|
entity_nodes = entity_descriptor['nodes'] or []
|
|
|
|
if not node_descriptor['id'] in entity_nodes:
|
|
logger.warning('Expected node to be added to entity')
|
|
is_valid = False
|
|
|
|
return is_valid
|
|
|
|
|
|
def main():
|
|
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
|
|
|
|
src_entities_dir_path = os.path.abspath(sys.argv[1])
|
|
dest_entities_dir_path = os.path.abspath(sys.argv[2])
|
|
|
|
logger.info('Unpacking to %s' % dest_entities_dir_path)
|
|
try:
|
|
unpack_entities(src_entities_dir_path, dest_entities_dir_path)
|
|
except InvalidEntitiesDetected:
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|